示例#1
0
/*
 * copy the data in 'item' into the btree
 */
int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
		      *root, struct btrfs_key *key, struct btrfs_root_item
		      *item)
{
	struct btrfs_path *path;
	struct extent_buffer *l;
	int ret;
	int slot;
	unsigned long ptr;

	path = btrfs_alloc_path();
	BUG_ON(!path);
	ret = btrfs_search_slot(trans, root, key, path, 0, 1);
	if (ret < 0)
		goto out;

	if (ret != 0) {
		btrfs_print_leaf(root, path->nodes[0]);
		printk(KERN_CRIT "unable to update root key %llu %u %llu\n",
		       (unsigned long long)key->objectid, key->type,
		       (unsigned long long)key->offset);
		BUG_ON(1);
	}

	l = path->nodes[0];
	slot = path->slots[0];
	ptr = btrfs_item_ptr_offset(l, slot);
	write_extent_buffer(l, item, ptr, sizeof(*item));
	btrfs_mark_buffer_dirty(path->nodes[0]);
out:
	btrfs_free_path(path);
	return ret;
}
示例#2
0
int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
		      *root, struct btrfs_key *key, struct btrfs_root_item
		      *item)
{
	struct btrfs_path *path;
	struct extent_buffer *l;
	int ret;
	int slot;
	unsigned long ptr;

	path = btrfs_alloc_path();
	BUG_ON(!path);
	ret = btrfs_search_slot(trans, root, key, path, 0, 1);
	if (ret < 0)
		goto out;
	BUG_ON(ret != 0);
	l = path->nodes[0];
	slot = path->slots[0];
	ptr = btrfs_item_ptr_offset(l, slot);
	write_extent_buffer(l, item, ptr, sizeof(*item));
	btrfs_mark_buffer_dirty(path->nodes[0]);
out:
	btrfs_release_path(root, path);
	btrfs_free_path(path);
	return ret;
}
static void free_space_set_bits(struct btrfs_block_group_cache *block_group,
                                struct btrfs_path *path, u64 *start, u64 *size,
                                int bit)
{
    struct extent_buffer *leaf;
    struct btrfs_key key;
    u64 end = *start + *size;
    u64 found_start, found_end;
    unsigned long ptr, first, last;

    leaf = path->nodes[0];
    btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
    ASSERT(key.type == BTRFS_FREE_SPACE_BITMAP_KEY);

    found_start = key.objectid;
    found_end = key.objectid + key.offset;
    ASSERT(*start >= found_start && *start < found_end);
    ASSERT(end > found_start);

    if (end > found_end)
        end = found_end;

    ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
    first = div_u64(*start - found_start, block_group->sectorsize);
    last = div_u64(end - found_start, block_group->sectorsize);
    if (bit)
        extent_buffer_bitmap_set(leaf, ptr, first, last - first);
    else
        extent_buffer_bitmap_clear(leaf, ptr, first, last - first);
    btrfs_mark_buffer_dirty(leaf);

    *size -= end - *start;
    *start = end;
}
示例#4
0
/*
 * given a pointer into a directory item, delete it.  This
 * handles items that have more than one entry in them.
 */
int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
			      struct btrfs_root *root,
			      struct btrfs_path *path,
			      struct btrfs_dir_item *di)
{

	struct extent_buffer *leaf;
	u32 sub_item_len;
	u32 item_len;
	int ret = 0;

	leaf = path->nodes[0];
	sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) +
		btrfs_dir_data_len(leaf, di);
	item_len = btrfs_item_size_nr(leaf, path->slots[0]);
	if (sub_item_len == item_len) {
		ret = btrfs_del_item(trans, root, path);
	} else {
		/* MARKER */
		unsigned long ptr = (unsigned long)di;
		unsigned long start;

		start = btrfs_item_ptr_offset(leaf, path->slots[0]);
		memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
			item_len - (ptr + sub_item_len - start));
		btrfs_truncate_item(trans, root, path,
				    item_len - sub_item_len, 1);
	}
	return ret;
}
示例#5
0
int find_name_in_backref(struct btrfs_path *path, const char * name,
			 int name_len, struct btrfs_inode_ref **ref_ret)
{
	struct extent_buffer *leaf;
	struct btrfs_inode_ref *ref;
	unsigned long ptr;
	unsigned long name_ptr;
	u32 item_size;
	u32 cur_offset = 0;
	int len;

	leaf = path->nodes[0];
	item_size = btrfs_item_size_nr(leaf, path->slots[0]);
	ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
	while (cur_offset < item_size) {
		ref = (struct btrfs_inode_ref *)(ptr + cur_offset);
		len = btrfs_inode_ref_name_len(leaf, ref);
		name_ptr = (unsigned long)(ref + 1);
		cur_offset += len + sizeof(*ref);
		if (len != name_len)
			continue;
		if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) {
			*ref_ret = ref;
			return 1;
		}
	}
	return 0;
}
示例#6
0
struct btrfs_root *btrfs_read_fs_root_no_cache(struct btrfs_fs_info *fs_info,
					       struct btrfs_key *location)
{
	struct btrfs_root *root;
	struct btrfs_root *tree_root = fs_info->tree_root;
	struct btrfs_path *path;
	struct extent_buffer *l;
	u64 generation;
	u32 blocksize;
	int ret = 0;

	root = malloc(sizeof(*root));
	if (!root)
		return ERR_PTR(-ENOMEM);
	memset(root, 0, sizeof(*root));
	if (location->offset == (u64)-1) {
		ret = find_and_setup_root(tree_root, fs_info,
					  location->objectid, root);
		if (ret) {
			free(root);
			return ERR_PTR(ret);
		}
		goto insert;
	}

	__setup_root(tree_root->nodesize, tree_root->leafsize,
		     tree_root->sectorsize, tree_root->stripesize,
		     root, fs_info, location->objectid);

	path = btrfs_alloc_path();
	BUG_ON(!path);
	ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0);
	if (ret != 0) {
		if (ret > 0)
			ret = -ENOENT;
		goto out;
	}
	l = path->nodes[0];
	read_extent_buffer(l, &root->root_item,
	       btrfs_item_ptr_offset(l, path->slots[0]),
	       sizeof(root->root_item));
	memcpy(&root->root_key, location, sizeof(*location));
	ret = 0;
out:
	btrfs_release_path(root, path);
	btrfs_free_path(path);
	if (ret) {
		free(root);
		return ERR_PTR(ret);
	}
	generation = btrfs_root_generation(&root->root_item);
	blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item));
	root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
				     blocksize, generation);
	BUG_ON(!root->node);
insert:
	root->ref_cows = 1;
	return root;
}
示例#7
0
文件: uuid-tree.c 项目: avagin/linux
/* return -ENOENT for !found, < 0 for errors, or 0 if an item was found */
static int btrfs_uuid_tree_lookup(struct btrfs_root *uuid_root, u8 *uuid,
				  u8 type, u64 subid)
{
	int ret;
	struct btrfs_path *path = NULL;
	struct extent_buffer *eb;
	int slot;
	u32 item_size;
	unsigned long offset;
	struct btrfs_key key;

	if (WARN_ON_ONCE(!uuid_root)) {
		ret = -ENOENT;
		goto out;
	}

	path = btrfs_alloc_path();
	if (!path) {
		ret = -ENOMEM;
		goto out;
	}

	btrfs_uuid_to_key(uuid, type, &key);
	ret = btrfs_search_slot(NULL, uuid_root, &key, path, 0, 0);
	if (ret < 0) {
		goto out;
	} else if (ret > 0) {
		ret = -ENOENT;
		goto out;
	}

	eb = path->nodes[0];
	slot = path->slots[0];
	item_size = btrfs_item_size_nr(eb, slot);
	offset = btrfs_item_ptr_offset(eb, slot);
	ret = -ENOENT;

	if (!IS_ALIGNED(item_size, sizeof(u64))) {
		btrfs_warn(uuid_root->fs_info,
			   "uuid item with illegal size %lu!",
			   (unsigned long)item_size);
		goto out;
	}
	while (item_size) {
		__le64 data;

		read_extent_buffer(eb, &data, offset, sizeof(data));
		if (le64_to_cpu(data) == subid) {
			ret = 0;
			break;
		}
		offset += sizeof(data);
		item_size -= sizeof(data);
	}

out:
	btrfs_free_path(path);
	return ret;
}
示例#8
0
int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
			   struct btrfs_root *root,
			   const char *name, int name_len,
			   u64 inode_objectid, u64 ref_objectid, u64 *index)
{
	struct btrfs_path *path;
	struct btrfs_key key;
	struct btrfs_inode_ref *ref;
	struct extent_buffer *leaf;
	unsigned long ptr;
	unsigned long item_start;
	u32 item_size;
	u32 sub_item_len;
	int ret;
	int del_len = name_len + sizeof(*ref);

	key.objectid = inode_objectid;
	key.offset = ref_objectid;
	btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY);

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

	path->leave_spinning = 1;

	ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
	if (ret > 0) {
		ret = -ENOENT;
		goto out;
	} else if (ret < 0) {
		goto out;
	}
	if (!find_name_in_backref(path, name, name_len, &ref)) {
		ret = -ENOENT;
		goto out;
	}
	leaf = path->nodes[0];
	item_size = btrfs_item_size_nr(leaf, path->slots[0]);

	if (index)
		*index = btrfs_inode_ref_index(leaf, ref);

	if (del_len == item_size) {
		ret = btrfs_del_item(trans, root, path);
		goto out;
	}
	ptr = (unsigned long)ref;
	sub_item_len = name_len + sizeof(*ref);
	item_start = btrfs_item_ptr_offset(leaf, path->slots[0]);
	memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
			      item_size - (ptr + sub_item_len - item_start));
	btrfs_truncate_item(trans, root, path,
				  item_size - sub_item_len, 1);
out:
	btrfs_free_path(path);
	return ret;
}
示例#9
0
/*
 * lookup the root with the highest offset for a given objectid.  The key we do
 * find is copied into 'key'.  If we find something return 0, otherwise 1, < 0
 * on error.
 */
int btrfs_find_last_root(struct btrfs_root *root, u64 objectid,
			struct btrfs_root_item *item, struct btrfs_key *key)
{
	struct btrfs_path *path;
	struct btrfs_key search_key;
	struct btrfs_key found_key;
	struct extent_buffer *l;
	int ret;
	int slot;

	search_key.objectid = objectid;
	search_key.type = BTRFS_ROOT_ITEM_KEY;
	search_key.offset = (u64)-1;

	path = btrfs_alloc_path();
	if (!path)
		return -ENOMEM;
	ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
	if (ret < 0)
		goto out;

	BUG_ON(ret == 0);
	if (path->slots[0] == 0) {
		ret = 1;
		goto out;
	}
	l = path->nodes[0];
	slot = path->slots[0] - 1;
	btrfs_item_key_to_cpu(l, &found_key, slot);
	if (found_key.objectid != objectid ||
	    found_key.type != BTRFS_ROOT_ITEM_KEY) {
		ret = 1;
		goto out;
	}
	if (item)
		read_extent_buffer(l, item, btrfs_item_ptr_offset(l, slot),
				   sizeof(*item));
	if (key)
		memcpy(key, &found_key, sizeof(found_key));
	ret = 0;
out:
	btrfs_free_path(path);
	return ret;
}
int free_space_test_bit(struct btrfs_block_group_cache *block_group,
                        struct btrfs_path *path, u64 offset)
{
    struct extent_buffer *leaf;
    struct btrfs_key key;
    u64 found_start, found_end;
    unsigned long ptr, i;

    leaf = path->nodes[0];
    btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
    ASSERT(key.type == BTRFS_FREE_SPACE_BITMAP_KEY);

    found_start = key.objectid;
    found_end = key.objectid + key.offset;
    ASSERT(offset >= found_start && offset < found_end);

    ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
    i = div_u64(offset - found_start, block_group->sectorsize);
    return !!extent_buffer_test_bit(leaf, ptr, i);
}
示例#11
0
文件: uuid-tree.c 项目: avagin/linux
int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans, u8 *uuid, u8 type,
			u64 subid_cpu)
{
	struct btrfs_fs_info *fs_info = trans->fs_info;
	struct btrfs_root *uuid_root = fs_info->uuid_root;
	int ret;
	struct btrfs_path *path = NULL;
	struct btrfs_key key;
	struct extent_buffer *eb;
	int slot;
	unsigned long offset;
	__le64 subid_le;

	ret = btrfs_uuid_tree_lookup(uuid_root, uuid, type, subid_cpu);
	if (ret != -ENOENT)
		return ret;

	if (WARN_ON_ONCE(!uuid_root)) {
		ret = -EINVAL;
		goto out;
	}

	btrfs_uuid_to_key(uuid, type, &key);

	path = btrfs_alloc_path();
	if (!path) {
		ret = -ENOMEM;
		goto out;
	}

	ret = btrfs_insert_empty_item(trans, uuid_root, path, &key,
				      sizeof(subid_le));
	if (ret >= 0) {
		/* Add an item for the type for the first time */
		eb = path->nodes[0];
		slot = path->slots[0];
		offset = btrfs_item_ptr_offset(eb, slot);
	} else if (ret == -EEXIST) {
		/*
		 * An item with that type already exists.
		 * Extend the item and store the new subid at the end.
		 */
		btrfs_extend_item(path, sizeof(subid_le));
		eb = path->nodes[0];
		slot = path->slots[0];
		offset = btrfs_item_ptr_offset(eb, slot);
		offset += btrfs_item_size_nr(eb, slot) - sizeof(subid_le);
	} else {
		btrfs_warn(fs_info,
			   "insert uuid item failed %d (0x%016llx, 0x%016llx) type %u!",
			   ret, (unsigned long long)key.objectid,
			   (unsigned long long)key.offset, type);
		goto out;
	}

	ret = 0;
	subid_le = cpu_to_le64(subid_cpu);
	write_extent_buffer(eb, &subid_le, offset, sizeof(subid_le));
	btrfs_mark_buffer_dirty(eb);

out:
	btrfs_free_path(path);
	return ret;
}
示例#12
0
文件: uuid-tree.c 项目: avagin/linux
int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info,
			    int (*check_func)(struct btrfs_fs_info *, u8 *, u8,
					      u64))
{
	struct btrfs_root *root = fs_info->uuid_root;
	struct btrfs_key key;
	struct btrfs_path *path;
	int ret = 0;
	struct extent_buffer *leaf;
	int slot;
	u32 item_size;
	unsigned long offset;

	path = btrfs_alloc_path();
	if (!path) {
		ret = -ENOMEM;
		goto out;
	}

	key.objectid = 0;
	key.type = 0;
	key.offset = 0;

again_search_slot:
	ret = btrfs_search_forward(root, &key, path, BTRFS_OLDEST_GENERATION);
	if (ret) {
		if (ret > 0)
			ret = 0;
		goto out;
	}

	while (1) {
		cond_resched();
		leaf = path->nodes[0];
		slot = path->slots[0];
		btrfs_item_key_to_cpu(leaf, &key, slot);

		if (key.type != BTRFS_UUID_KEY_SUBVOL &&
		    key.type != BTRFS_UUID_KEY_RECEIVED_SUBVOL)
			goto skip;

		offset = btrfs_item_ptr_offset(leaf, slot);
		item_size = btrfs_item_size_nr(leaf, slot);
		if (!IS_ALIGNED(item_size, sizeof(u64))) {
			btrfs_warn(fs_info,
				   "uuid item with illegal size %lu!",
				   (unsigned long)item_size);
			goto skip;
		}
		while (item_size) {
			u8 uuid[BTRFS_UUID_SIZE];
			__le64 subid_le;
			u64 subid_cpu;

			put_unaligned_le64(key.objectid, uuid);
			put_unaligned_le64(key.offset, uuid + sizeof(u64));
			read_extent_buffer(leaf, &subid_le, offset,
					   sizeof(subid_le));
			subid_cpu = le64_to_cpu(subid_le);
			ret = check_func(fs_info, uuid, key.type, subid_cpu);
			if (ret < 0)
				goto out;
			if (ret > 0) {
				btrfs_release_path(path);
				ret = btrfs_uuid_iter_rem(root, uuid, key.type,
							  subid_cpu);
				if (ret == 0) {
					/*
					 * this might look inefficient, but the
					 * justification is that it is an
					 * exception that check_func returns 1,
					 * and that in the regular case only one
					 * entry per UUID exists.
					 */
					goto again_search_slot;
				}
				if (ret < 0 && ret != -ENOENT)
					goto out;
			}
			item_size -= sizeof(subid_le);
			offset += sizeof(subid_le);
		}

skip:
		ret = btrfs_next_item(root, path);
		if (ret == 0)
			continue;
		else if (ret > 0)
			ret = 0;
		break;
	}

out:
	btrfs_free_path(path);
	return ret;
}
示例#13
0
文件: uuid-tree.c 项目: avagin/linux
int btrfs_uuid_tree_remove(struct btrfs_trans_handle *trans, u8 *uuid, u8 type,
			u64 subid)
{
	struct btrfs_fs_info *fs_info = trans->fs_info;
	struct btrfs_root *uuid_root = fs_info->uuid_root;
	int ret;
	struct btrfs_path *path = NULL;
	struct btrfs_key key;
	struct extent_buffer *eb;
	int slot;
	unsigned long offset;
	u32 item_size;
	unsigned long move_dst;
	unsigned long move_src;
	unsigned long move_len;

	if (WARN_ON_ONCE(!uuid_root)) {
		ret = -EINVAL;
		goto out;
	}

	btrfs_uuid_to_key(uuid, type, &key);

	path = btrfs_alloc_path();
	if (!path) {
		ret = -ENOMEM;
		goto out;
	}

	ret = btrfs_search_slot(trans, uuid_root, &key, path, -1, 1);
	if (ret < 0) {
		btrfs_warn(fs_info, "error %d while searching for uuid item!",
			   ret);
		goto out;
	}
	if (ret > 0) {
		ret = -ENOENT;
		goto out;
	}

	eb = path->nodes[0];
	slot = path->slots[0];
	offset = btrfs_item_ptr_offset(eb, slot);
	item_size = btrfs_item_size_nr(eb, slot);
	if (!IS_ALIGNED(item_size, sizeof(u64))) {
		btrfs_warn(fs_info, "uuid item with illegal size %lu!",
			   (unsigned long)item_size);
		ret = -ENOENT;
		goto out;
	}
	while (item_size) {
		__le64 read_subid;

		read_extent_buffer(eb, &read_subid, offset, sizeof(read_subid));
		if (le64_to_cpu(read_subid) == subid)
			break;
		offset += sizeof(read_subid);
		item_size -= sizeof(read_subid);
	}

	if (!item_size) {
		ret = -ENOENT;
		goto out;
	}

	item_size = btrfs_item_size_nr(eb, slot);
	if (item_size == sizeof(subid)) {
		ret = btrfs_del_item(trans, uuid_root, path);
		goto out;
	}

	move_dst = offset;
	move_src = offset + sizeof(subid);
	move_len = item_size - (move_src - btrfs_item_ptr_offset(eb, slot));
	memmove_extent_buffer(eb, move_dst, move_src, move_len);
	btrfs_truncate_item(path, item_size - sizeof(subid), 1);

out:
	btrfs_free_path(path);
	return ret;
}
示例#14
0
static int iterate_inode_extrefs(u64 inum, struct btrfs_root *fs_root,
				 struct btrfs_path *path,
				 iterate_irefs_t *iterate, void *ctx)
{
	int ret;
	int slot;
	u64 offset = 0;
	u64 parent;
	int found = 0;
	struct extent_buffer *eb;
	struct btrfs_inode_extref *extref;
	struct extent_buffer *leaf;
	u32 item_size;
	u32 cur_offset;
	unsigned long ptr;

	while (1) {
		ret = btrfs_find_one_extref(fs_root, inum, offset, path, &extref,
					    &offset);
		if (ret < 0)
			break;
		if (ret) {
			ret = found ? 0 : -ENOENT;
			break;
		}
		++found;

		slot = path->slots[0];
		eb = path->nodes[0];
		/* make sure we can use eb after releasing the path */
		atomic_inc(&eb->refs);

		btrfs_tree_read_lock(eb);
		btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
		btrfs_release_path(path);

		leaf = path->nodes[0];
		item_size = btrfs_item_size_nr(leaf, path->slots[0]);
		ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
		cur_offset = 0;

		while (cur_offset < item_size) {
			u32 name_len;

			extref = (struct btrfs_inode_extref *)(ptr + cur_offset);
			parent = btrfs_inode_extref_parent(eb, extref);
			name_len = btrfs_inode_extref_name_len(eb, extref);
			ret = iterate(parent, name_len,
				      (unsigned long)&extref->name, eb, ctx);
			if (ret)
				break;

			cur_offset += btrfs_inode_extref_name_len(leaf, extref);
			cur_offset += sizeof(*extref);
		}
		btrfs_tree_read_unlock_blocking(eb);
		free_extent_buffer(eb);

		offset++;
	}

	btrfs_release_path(path);

	return ret;
}
示例#15
0
文件: dedup.c 项目: quadcores/test
static int ondisk_add(struct btrfs_trans_handle *trans,
		      struct btrfs_dedup_info *dedup_info,
		      struct btrfs_dedup_hash *hash)
{
	struct btrfs_path *path;
	struct btrfs_root *dedup_root = dedup_info->dedup_root;
	struct btrfs_key key;
	struct btrfs_dedup_hash_item *hash_item;
	u64 bytenr;
	u32 num_bytes;
	int hash_len = btrfs_dedup_sizes[dedup_info->hash_type];
	int ret;

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

	mutex_lock(&dedup_info->lock);

	ret = ondisk_search_bytenr(NULL, dedup_info, path, hash->bytenr, 0);
	if (ret < 0)
		goto out;
	if (ret > 0) {
		ret = 0;
		goto out;
	}
	btrfs_release_path(path);

	ret = ondisk_search_hash(dedup_info, hash->hash, &bytenr, &num_bytes);
	if (ret < 0)
		goto out;
	/* Same hash found, don't re-add to save dedup tree space */
	if (ret > 0) {
		ret = 0;
		goto out;
	}

	/* Insert hash->bytenr item */
	memcpy(&key.objectid, hash->hash + hash_len - 8, 8);
	key.type = BTRFS_DEDUP_HASH_ITEM_KEY;
	key.offset = hash->bytenr;

	ret = btrfs_insert_empty_item(trans, dedup_root, path, &key,
			sizeof(*hash_item) + hash_len);
	WARN_ON(ret == -EEXIST);
	if (ret < 0)
		goto out;
	hash_item = btrfs_item_ptr(path->nodes[0], path->slots[0],
				   struct btrfs_dedup_hash_item);
	btrfs_set_dedup_hash_len(path->nodes[0], hash_item, hash->num_bytes);
	write_extent_buffer(path->nodes[0], hash->hash,
			    (unsigned long)(hash_item + 1), hash_len);
	btrfs_mark_buffer_dirty(path->nodes[0]);
	btrfs_release_path(path);

	/* Then bytenr->hash item */
	key.objectid = hash->bytenr;
	key.type = BTRFS_DEDUP_BYTENR_ITEM_KEY;
	memcpy(&key.offset, hash->hash + hash_len - 8, 8);

	ret = btrfs_insert_empty_item(trans, dedup_root, path, &key, hash_len);
	WARN_ON(ret == -EEXIST);
	if (ret < 0)
		goto out;
	write_extent_buffer(path->nodes[0], hash->hash,
			btrfs_item_ptr_offset(path->nodes[0], path->slots[0]),
			hash_len);
	btrfs_mark_buffer_dirty(path->nodes[0]);

out:
	mutex_unlock(&dedup_info->lock);
	btrfs_free_path(path);
	return ret;
}
示例#16
0
void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
{
	int i;
	char *str;
	struct btrfs_item *item;
	struct btrfs_dir_item *di;
	struct btrfs_inode_item *ii;
	struct btrfs_file_extent_item *fi;
	struct btrfs_block_group_item *bi;
	struct btrfs_extent_data_ref *dref;
	struct btrfs_shared_data_ref *sref;
	struct btrfs_inode_ref *iref;
	struct btrfs_inode_extref *iref2;
	struct btrfs_dev_extent *dev_extent;
	struct btrfs_disk_key disk_key;
	struct btrfs_block_group_item bg_item;
	struct btrfs_dir_log_item *dlog;
	struct btrfs_qgroup_info_item *qg_info;
	struct btrfs_qgroup_limit_item *qg_limit;
	struct btrfs_qgroup_status_item *qg_status;
	u32 nr = btrfs_header_nritems(l);
	u64 objectid;
	u32 type;

	printf("leaf %llu items %d free space %d generation %llu owner %llu\n",
		(unsigned long long)btrfs_header_bytenr(l), nr,
		btrfs_leaf_free_space(root, l),
		(unsigned long long)btrfs_header_generation(l),
		(unsigned long long)btrfs_header_owner(l));
	print_uuids(l);
	fflush(stdout);
	for (i = 0 ; i < nr ; i++) {
		item = btrfs_item_nr(l, i);
		btrfs_item_key(l, &disk_key, i);
		objectid = btrfs_disk_key_objectid(&disk_key);
		type = btrfs_disk_key_type(&disk_key);
		printf("\titem %d ", i);
		btrfs_print_key(&disk_key);
		printf(" itemoff %d itemsize %d\n",
			btrfs_item_offset(l, item),
			btrfs_item_size(l, item));

		if (type == 0 && objectid == BTRFS_FREE_SPACE_OBJECTID)
			print_free_space_header(l, i);

		switch (type) {
		case BTRFS_INODE_ITEM_KEY:
			ii = btrfs_item_ptr(l, i, struct btrfs_inode_item);
			printf("\t\tinode generation %llu transid %llu size %llu block group %llu mode %o links %u\n",
			       (unsigned long long)btrfs_inode_generation(l, ii),
			       (unsigned long long)btrfs_inode_transid(l, ii),
			       (unsigned long long)btrfs_inode_size(l, ii),
			       (unsigned long long)btrfs_inode_block_group(l,ii),
			       btrfs_inode_mode(l, ii),
			       btrfs_inode_nlink(l, ii));
			break;
		case BTRFS_INODE_REF_KEY:
			iref = btrfs_item_ptr(l, i, struct btrfs_inode_ref);
			print_inode_ref_item(l, item, iref);
			break;
		case BTRFS_INODE_EXTREF_KEY:
			iref2 = btrfs_item_ptr(l, i, struct btrfs_inode_extref);
			print_inode_extref_item(l, item, iref2);
			break;
		case BTRFS_DIR_ITEM_KEY:
		case BTRFS_DIR_INDEX_KEY:
		case BTRFS_XATTR_ITEM_KEY:
			di = btrfs_item_ptr(l, i, struct btrfs_dir_item);
			print_dir_item(l, item, di);
			break;
		case BTRFS_DIR_LOG_INDEX_KEY:
		case BTRFS_DIR_LOG_ITEM_KEY:
			dlog = btrfs_item_ptr(l, i, struct btrfs_dir_log_item);
			printf("\t\tdir log end %Lu\n",
			       (unsigned long long)btrfs_dir_log_end(l, dlog));
		       break;
		case BTRFS_ORPHAN_ITEM_KEY:
			printf("\t\torphan item\n");
			break;
		case BTRFS_ROOT_ITEM_KEY:
			print_root(l, i);
			break;
		case BTRFS_ROOT_REF_KEY:
			print_root_ref(l, i, "ref");
			break;
		case BTRFS_ROOT_BACKREF_KEY:
			print_root_ref(l, i, "backref");
			break;
		case BTRFS_EXTENT_ITEM_KEY:
			print_extent_item(l, i, 0);
			break;
		case BTRFS_METADATA_ITEM_KEY:
			print_extent_item(l, i, 1);
			break;
		case BTRFS_TREE_BLOCK_REF_KEY:
			printf("\t\ttree block backref\n");
			break;
		case BTRFS_SHARED_BLOCK_REF_KEY:
			printf("\t\tshared block backref\n");
			break;
		case BTRFS_EXTENT_DATA_REF_KEY:
			dref = btrfs_item_ptr(l, i, struct btrfs_extent_data_ref);
			printf("\t\textent data backref root %llu "
			       "objectid %llu offset %llu count %u\n",
			       (unsigned long long)btrfs_extent_data_ref_root(l, dref),
			       (unsigned long long)btrfs_extent_data_ref_objectid(l, dref),
			       (unsigned long long)btrfs_extent_data_ref_offset(l, dref),
			       btrfs_extent_data_ref_count(l, dref));
			break;
		case BTRFS_SHARED_DATA_REF_KEY:
			sref = btrfs_item_ptr(l, i, struct btrfs_shared_data_ref);
			printf("\t\tshared data backref count %u\n",
			       btrfs_shared_data_ref_count(l, sref));
			break;
		case BTRFS_EXTENT_REF_V0_KEY:
#ifdef BTRFS_COMPAT_EXTENT_TREE_V0
			print_extent_ref_v0(l, i);
#else
			BUG();
#endif
			break;
		case BTRFS_CSUM_ITEM_KEY:
			printf("\t\tcsum item\n");
			break;
		case BTRFS_EXTENT_CSUM_KEY:
			printf("\t\textent csum item\n");
			break;
		case BTRFS_EXTENT_DATA_KEY:
			fi = btrfs_item_ptr(l, i,
					    struct btrfs_file_extent_item);
			print_file_extent_item(l, item, fi);
			break;
		case BTRFS_BLOCK_GROUP_ITEM_KEY:
			bi = btrfs_item_ptr(l, i,
					    struct btrfs_block_group_item);
			read_extent_buffer(l, &bg_item, (unsigned long)bi,
					   sizeof(bg_item));
			printf("\t\tblock group used %llu chunk_objectid %llu flags %llu\n",
			       (unsigned long long)btrfs_block_group_used(&bg_item),
			       (unsigned long long)btrfs_block_group_chunk_objectid(&bg_item),
			       (unsigned long long)btrfs_block_group_flags(&bg_item));
			break;
		case BTRFS_CHUNK_ITEM_KEY:
			print_chunk(l, btrfs_item_ptr(l, i, struct btrfs_chunk));
			break;
		case BTRFS_DEV_ITEM_KEY:
			print_dev_item(l, btrfs_item_ptr(l, i,
					struct btrfs_dev_item));
			break;
		case BTRFS_DEV_EXTENT_KEY:
			dev_extent = btrfs_item_ptr(l, i,
						    struct btrfs_dev_extent);
			printf("\t\tdev extent chunk_tree %llu\n"
			       "\t\tchunk objectid %llu chunk offset %llu "
			       "length %llu\n",
			       (unsigned long long)
			       btrfs_dev_extent_chunk_tree(l, dev_extent),
			       (unsigned long long)
			       btrfs_dev_extent_chunk_objectid(l, dev_extent),
			       (unsigned long long)
			       btrfs_dev_extent_chunk_offset(l, dev_extent),
			       (unsigned long long)
			       btrfs_dev_extent_length(l, dev_extent));
			break;
		case BTRFS_QGROUP_STATUS_KEY:
			qg_status = btrfs_item_ptr(l, i,
					struct btrfs_qgroup_status_item);
			printf("\t\tversion %llu generation %llu flags %#llx "
				"scan %lld\n",
				(unsigned long long)
				btrfs_qgroup_status_version(l, qg_status),
				(unsigned long long)
				btrfs_qgroup_status_generation(l, qg_status),
				(unsigned long long)
				btrfs_qgroup_status_flags(l, qg_status),
				(unsigned long long)
				btrfs_qgroup_status_scan(l, qg_status));
			break;
		case BTRFS_QGROUP_RELATION_KEY:
			break;
		case BTRFS_QGROUP_INFO_KEY:
			qg_info = btrfs_item_ptr(l, i,
						 struct btrfs_qgroup_info_item);
			printf("\t\tgeneration %llu\n"
			     "\t\treferenced %lld referenced compressed %lld\n"
			     "\t\texclusive %lld exclusive compressed %lld\n",
			       (unsigned long long)
			       btrfs_qgroup_info_generation(l, qg_info),
			       (long long)
			       btrfs_qgroup_info_referenced(l, qg_info),
			       (long long)
			       btrfs_qgroup_info_referenced_compressed(l,
								       qg_info),
			       (long long)
			       btrfs_qgroup_info_exclusive(l, qg_info),
			       (long long)
			       btrfs_qgroup_info_exclusive_compressed(l,
								      qg_info));
			break;
		case BTRFS_QGROUP_LIMIT_KEY:
			qg_limit = btrfs_item_ptr(l, i,
					 struct btrfs_qgroup_limit_item);
			printf("\t\tflags %llx\n"
			     "\t\tmax referenced %lld max exclusive %lld\n"
			     "\t\trsv referenced %lld rsv exclusive %lld\n",
			       (unsigned long long)
			       btrfs_qgroup_limit_flags(l, qg_limit),
			       (long long)
			       btrfs_qgroup_limit_max_referenced(l, qg_limit),
			       (long long)
			       btrfs_qgroup_limit_max_exclusive(l, qg_limit),
			       (long long)
			       btrfs_qgroup_limit_rsv_referenced(l, qg_limit),
			       (long long)
			       btrfs_qgroup_limit_rsv_exclusive(l, qg_limit));
			break;
		case BTRFS_STRING_ITEM_KEY:
			/* dirty, but it's simple */
			str = l->data + btrfs_item_ptr_offset(l, i);
			printf("\t\titem data %.*s\n", btrfs_item_size(l, item), str);
			break;
		case BTRFS_DEV_STATS_KEY:
			printf("\t\tdevice stats\n");
			break;
		};
		fflush(stdout);
	}
}
int convert_free_space_to_extents(struct btrfs_trans_handle *trans,
                                  struct btrfs_fs_info *fs_info,
                                  struct btrfs_block_group_cache *block_group,
                                  struct btrfs_path *path)
{
    struct btrfs_root *root = fs_info->free_space_root;
    struct btrfs_free_space_info *info;
    struct btrfs_key key, found_key;
    struct extent_buffer *leaf;
    unsigned long *bitmap;
    u64 start, end;
    /* Initialize to silence GCC. */
    u64 extent_start = 0;
    u64 offset;
    u32 bitmap_size, flags, expected_extent_count;
    int prev_bit = 0, bit, bitnr;
    u32 extent_count = 0;
    int done = 0, nr;
    int ret;

    bitmap_size = free_space_bitmap_size(block_group->key.offset,
                                         block_group->sectorsize);
    bitmap = alloc_bitmap(bitmap_size);
    if (!bitmap) {
        ret = -ENOMEM;
        goto out;
    }

    start = block_group->key.objectid;
    end = block_group->key.objectid + block_group->key.offset;

    key.objectid = end - 1;
    key.type = (u8)-1;
    key.offset = (u64)-1;

    while (!done) {
        ret = btrfs_search_prev_slot(trans, root, &key, path, -1, 1);
        if (ret)
            goto out;

        leaf = path->nodes[0];
        nr = 0;
        path->slots[0]++;
        while (path->slots[0] > 0) {
            btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0] - 1);

            if (found_key.type == BTRFS_FREE_SPACE_INFO_KEY) {
                ASSERT(found_key.objectid == block_group->key.objectid);
                ASSERT(found_key.offset == block_group->key.offset);
                done = 1;
                break;
            } else if (found_key.type == BTRFS_FREE_SPACE_BITMAP_KEY) {
                unsigned long ptr;
                char *bitmap_cursor;
                u32 bitmap_pos, data_size;

                ASSERT(found_key.objectid >= start);
                ASSERT(found_key.objectid < end);
                ASSERT(found_key.objectid + found_key.offset <= end);

                bitmap_pos = div_u64(found_key.objectid - start,
                                     block_group->sectorsize *
                                     BITS_PER_BYTE);
                bitmap_cursor = ((char *)bitmap) + bitmap_pos;
                data_size = free_space_bitmap_size(found_key.offset,
                                                   block_group->sectorsize);

                ptr = btrfs_item_ptr_offset(leaf, path->slots[0] - 1);
                read_extent_buffer(leaf, bitmap_cursor, ptr,
                                   data_size);

                nr++;
                path->slots[0]--;
            } else {
                ASSERT(0);
            }
        }

        ret = btrfs_del_items(trans, root, path, path->slots[0], nr);
        if (ret)
            goto out;
        btrfs_release_path(path);
    }

    info = search_free_space_info(trans, fs_info, block_group, path, 1);
    if (IS_ERR(info)) {
        ret = PTR_ERR(info);
        goto out;
    }
    leaf = path->nodes[0];
    flags = btrfs_free_space_flags(leaf, info);
    flags &= ~BTRFS_FREE_SPACE_USING_BITMAPS;
    btrfs_set_free_space_flags(leaf, info, flags);
    expected_extent_count = btrfs_free_space_extent_count(leaf, info);
    btrfs_mark_buffer_dirty(leaf);
    btrfs_release_path(path);

    offset = start;
    bitnr = 0;
    while (offset < end) {
        bit = !!test_bit(bitnr, bitmap);
        if (prev_bit == 0 && bit == 1) {
            extent_start = offset;
        } else if (prev_bit == 1 && bit == 0) {
            key.objectid = extent_start;
            key.type = BTRFS_FREE_SPACE_EXTENT_KEY;
            key.offset = offset - extent_start;

            ret = btrfs_insert_empty_item(trans, root, path, &key, 0);
            if (ret)
                goto out;
            btrfs_release_path(path);

            extent_count++;
        }
        prev_bit = bit;
        offset += block_group->sectorsize;
        bitnr++;
    }
    if (prev_bit == 1) {
        key.objectid = extent_start;
        key.type = BTRFS_FREE_SPACE_EXTENT_KEY;
        key.offset = end - extent_start;

        ret = btrfs_insert_empty_item(trans, root, path, &key, 0);
        if (ret)
            goto out;
        btrfs_release_path(path);

        extent_count++;
    }

    if (extent_count != expected_extent_count) {
        btrfs_err(fs_info, "incorrect extent count for %llu; counted %u, expected %u",
                  block_group->key.objectid, extent_count,
                  expected_extent_count);
        ASSERT(0);
        ret = -EIO;
        goto out;
    }

    ret = 0;
out:
    kvfree(bitmap);
    if (ret)
        btrfs_abort_transaction(trans, ret);
    return ret;
}
int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans,
                                  struct btrfs_fs_info *fs_info,
                                  struct btrfs_block_group_cache *block_group,
                                  struct btrfs_path *path)
{
    struct btrfs_root *root = fs_info->free_space_root;
    struct btrfs_free_space_info *info;
    struct btrfs_key key, found_key;
    struct extent_buffer *leaf;
    unsigned long *bitmap;
    char *bitmap_cursor;
    u64 start, end;
    u64 bitmap_range, i;
    u32 bitmap_size, flags, expected_extent_count;
    u32 extent_count = 0;
    int done = 0, nr;
    int ret;

    bitmap_size = free_space_bitmap_size(block_group->key.offset,
                                         block_group->sectorsize);
    bitmap = alloc_bitmap(bitmap_size);
    if (!bitmap) {
        ret = -ENOMEM;
        goto out;
    }

    start = block_group->key.objectid;
    end = block_group->key.objectid + block_group->key.offset;

    key.objectid = end - 1;
    key.type = (u8)-1;
    key.offset = (u64)-1;

    while (!done) {
        ret = btrfs_search_prev_slot(trans, root, &key, path, -1, 1);
        if (ret)
            goto out;

        leaf = path->nodes[0];
        nr = 0;
        path->slots[0]++;
        while (path->slots[0] > 0) {
            btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0] - 1);

            if (found_key.type == BTRFS_FREE_SPACE_INFO_KEY) {
                ASSERT(found_key.objectid == block_group->key.objectid);
                ASSERT(found_key.offset == block_group->key.offset);
                done = 1;
                break;
            } else if (found_key.type == BTRFS_FREE_SPACE_EXTENT_KEY) {
                u64 first, last;

                ASSERT(found_key.objectid >= start);
                ASSERT(found_key.objectid < end);
                ASSERT(found_key.objectid + found_key.offset <= end);

                first = div_u64(found_key.objectid - start,
                                block_group->sectorsize);
                last = div_u64(found_key.objectid + found_key.offset - start,
                               block_group->sectorsize);
                bitmap_set(bitmap, first, last - first);

                extent_count++;
                nr++;
                path->slots[0]--;
            } else {
                ASSERT(0);
            }
        }

        ret = btrfs_del_items(trans, root, path, path->slots[0], nr);
        if (ret)
            goto out;
        btrfs_release_path(path);
    }

    info = search_free_space_info(trans, fs_info, block_group, path, 1);
    if (IS_ERR(info)) {
        ret = PTR_ERR(info);
        goto out;
    }
    leaf = path->nodes[0];
    flags = btrfs_free_space_flags(leaf, info);
    flags |= BTRFS_FREE_SPACE_USING_BITMAPS;
    btrfs_set_free_space_flags(leaf, info, flags);
    expected_extent_count = btrfs_free_space_extent_count(leaf, info);
    btrfs_mark_buffer_dirty(leaf);
    btrfs_release_path(path);

    if (extent_count != expected_extent_count) {
        btrfs_err(fs_info, "incorrect extent count for %llu; counted %u, expected %u",
                  block_group->key.objectid, extent_count,
                  expected_extent_count);
        ASSERT(0);
        ret = -EIO;
        goto out;
    }

    bitmap_cursor = (char *)bitmap;
    bitmap_range = block_group->sectorsize * BTRFS_FREE_SPACE_BITMAP_BITS;
    i = start;
    while (i < end) {
        unsigned long ptr;
        u64 extent_size;
        u32 data_size;

        extent_size = min(end - i, bitmap_range);
        data_size = free_space_bitmap_size(extent_size,
                                           block_group->sectorsize);

        key.objectid = i;
        key.type = BTRFS_FREE_SPACE_BITMAP_KEY;
        key.offset = extent_size;

        ret = btrfs_insert_empty_item(trans, root, path, &key,
                                      data_size);
        if (ret)
            goto out;

        leaf = path->nodes[0];
        ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
        write_extent_buffer(leaf, bitmap_cursor, ptr,
                            data_size);
        btrfs_mark_buffer_dirty(leaf);
        btrfs_release_path(path);

        i += extent_size;
        bitmap_cursor += data_size;
    }

    ret = 0;
out:
    kvfree(bitmap);
    if (ret)
        btrfs_abort_transaction(trans, ret);
    return ret;
}
示例#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[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;
}
示例#20
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;
}
示例#21
0
int make_btrfs(int fd, const char *device, const char *label,
	       u64 blocks[7], u64 num_bytes, u32 nodesize,
	       u32 leafsize, u32 sectorsize, u32 stripesize, u64 features)
{
	struct btrfs_super_block super;
	struct extent_buffer *buf;
	struct btrfs_root_item root_item;
	struct btrfs_disk_key disk_key;
	struct btrfs_extent_item *extent_item;
	struct btrfs_inode_item *inode_item;
	struct btrfs_chunk *chunk;
	struct btrfs_dev_item *dev_item;
	struct btrfs_dev_extent *dev_extent;
	u8 chunk_tree_uuid[BTRFS_UUID_SIZE];
	u8 *ptr;
	int i;
	int ret;
	u32 itemoff;
	u32 nritems = 0;
	u64 first_free;
	u64 ref_root;
	u32 array_size;
	u32 item_size;
	int skinny_metadata = !!(features &
				 BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA);

	first_free = BTRFS_SUPER_INFO_OFFSET + sectorsize * 2 - 1;
	first_free &= ~((u64)sectorsize - 1);

	memset(&super, 0, sizeof(super));

	num_bytes = (num_bytes / sectorsize) * sectorsize;
	uuid_generate(super.fsid);
	uuid_generate(super.dev_item.uuid);
	uuid_generate(chunk_tree_uuid);

	btrfs_set_super_bytenr(&super, blocks[0]);
	btrfs_set_super_num_devices(&super, 1);
	btrfs_set_super_magic(&super, BTRFS_MAGIC);
	btrfs_set_super_generation(&super, 1);
	btrfs_set_super_root(&super, blocks[1]);
	btrfs_set_super_chunk_root(&super, blocks[3]);
	btrfs_set_super_total_bytes(&super, num_bytes);
	btrfs_set_super_bytes_used(&super, 6 * leafsize);
	btrfs_set_super_sectorsize(&super, sectorsize);
	btrfs_set_super_leafsize(&super, leafsize);
	btrfs_set_super_nodesize(&super, nodesize);
	btrfs_set_super_stripesize(&super, stripesize);
	btrfs_set_super_csum_type(&super, BTRFS_CSUM_TYPE_CRC32);
	btrfs_set_super_chunk_root_generation(&super, 1);
	btrfs_set_super_cache_generation(&super, -1);
	btrfs_set_super_incompat_flags(&super, features);
	if (label)
		strncpy(super.label, label, BTRFS_LABEL_SIZE - 1);

	buf = malloc(sizeof(*buf) + max(sectorsize, leafsize));

	/* create the tree of root objects */
	memset(buf->data, 0, leafsize);
	buf->len = leafsize;
	btrfs_set_header_bytenr(buf, blocks[1]);
	btrfs_set_header_nritems(buf, 4);
	btrfs_set_header_generation(buf, 1);
	btrfs_set_header_backref_rev(buf, BTRFS_MIXED_BACKREF_REV);
	btrfs_set_header_owner(buf, BTRFS_ROOT_TREE_OBJECTID);
	write_extent_buffer(buf, super.fsid, btrfs_header_fsid(),
			    BTRFS_FSID_SIZE);

	write_extent_buffer(buf, chunk_tree_uuid, (unsigned long)
			    btrfs_header_chunk_tree_uuid(buf),
			    BTRFS_UUID_SIZE);

	/* create the items for the root tree */
	memset(&root_item, 0, sizeof(root_item));
	inode_item = &root_item.inode;
	btrfs_set_stack_inode_generation(inode_item, 1);
	btrfs_set_stack_inode_size(inode_item, 3);
	btrfs_set_stack_inode_nlink(inode_item, 1);
	btrfs_set_stack_inode_nbytes(inode_item, leafsize);
	btrfs_set_stack_inode_mode(inode_item, S_IFDIR | 0755);
	btrfs_set_root_refs(&root_item, 1);
	btrfs_set_root_used(&root_item, leafsize);
	btrfs_set_root_generation(&root_item, 1);

	memset(&disk_key, 0, sizeof(disk_key));
	btrfs_set_disk_key_type(&disk_key, BTRFS_ROOT_ITEM_KEY);
	btrfs_set_disk_key_offset(&disk_key, 0);
	nritems = 0;

	itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) - sizeof(root_item);
	btrfs_set_root_bytenr(&root_item, blocks[2]);
	btrfs_set_disk_key_objectid(&disk_key, BTRFS_EXTENT_TREE_OBJECTID);
	btrfs_set_item_key(buf, &disk_key, nritems);
	btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff);
	btrfs_set_item_size(buf, btrfs_item_nr(nritems),
			    sizeof(root_item));
	write_extent_buffer(buf, &root_item, btrfs_item_ptr_offset(buf,
			    nritems), sizeof(root_item));
	nritems++;

	itemoff = itemoff - sizeof(root_item);
	btrfs_set_root_bytenr(&root_item, blocks[4]);
	btrfs_set_disk_key_objectid(&disk_key, BTRFS_DEV_TREE_OBJECTID);
	btrfs_set_item_key(buf, &disk_key, nritems);
	btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff);
	btrfs_set_item_size(buf, btrfs_item_nr(nritems),
			    sizeof(root_item));
	write_extent_buffer(buf, &root_item,
			    btrfs_item_ptr_offset(buf, nritems),
			    sizeof(root_item));
	nritems++;

	itemoff = itemoff - sizeof(root_item);
	btrfs_set_root_bytenr(&root_item, blocks[5]);
	btrfs_set_disk_key_objectid(&disk_key, BTRFS_FS_TREE_OBJECTID);
	btrfs_set_item_key(buf, &disk_key, nritems);
	btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff);
	btrfs_set_item_size(buf, btrfs_item_nr(nritems),
			    sizeof(root_item));
	write_extent_buffer(buf, &root_item,
			    btrfs_item_ptr_offset(buf, nritems),
			    sizeof(root_item));
	nritems++;

	itemoff = itemoff - sizeof(root_item);
	btrfs_set_root_bytenr(&root_item, blocks[6]);
	btrfs_set_disk_key_objectid(&disk_key, BTRFS_CSUM_TREE_OBJECTID);
	btrfs_set_item_key(buf, &disk_key, nritems);
	btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff);
	btrfs_set_item_size(buf, btrfs_item_nr(nritems),
			    sizeof(root_item));
	write_extent_buffer(buf, &root_item,
			    btrfs_item_ptr_offset(buf, nritems),
			    sizeof(root_item));
	nritems++;


	csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
	ret = pwrite(fd, buf->data, leafsize, blocks[1]);
	if (ret != leafsize) {
		ret = (ret < 0 ? -errno : -EIO);
		goto out;
	}

	/* create the items for the extent tree */
	memset(buf->data+sizeof(struct btrfs_header), 0,
		leafsize-sizeof(struct btrfs_header));
	nritems = 0;
	itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize);
	for (i = 1; i < 7; i++) {
		item_size = sizeof(struct btrfs_extent_item);
		if (!skinny_metadata)
			item_size += sizeof(struct btrfs_tree_block_info);

		BUG_ON(blocks[i] < first_free);
		BUG_ON(blocks[i] < blocks[i - 1]);

		/* create extent item */
		itemoff -= item_size;
		btrfs_set_disk_key_objectid(&disk_key, blocks[i]);
		if (skinny_metadata) {
			btrfs_set_disk_key_type(&disk_key,
						BTRFS_METADATA_ITEM_KEY);
			btrfs_set_disk_key_offset(&disk_key, 0);
		} else {
			btrfs_set_disk_key_type(&disk_key,
						BTRFS_EXTENT_ITEM_KEY);
			btrfs_set_disk_key_offset(&disk_key, leafsize);
		}
		btrfs_set_item_key(buf, &disk_key, nritems);
		btrfs_set_item_offset(buf, btrfs_item_nr(nritems),
				      itemoff);
		btrfs_set_item_size(buf, btrfs_item_nr(nritems),
				    item_size);
		extent_item = btrfs_item_ptr(buf, nritems,
					     struct btrfs_extent_item);
		btrfs_set_extent_refs(buf, extent_item, 1);
		btrfs_set_extent_generation(buf, extent_item, 1);
		btrfs_set_extent_flags(buf, extent_item,
				       BTRFS_EXTENT_FLAG_TREE_BLOCK);
		nritems++;

		/* create extent ref */
		ref_root = reference_root_table[i];
		btrfs_set_disk_key_objectid(&disk_key, blocks[i]);
		btrfs_set_disk_key_offset(&disk_key, ref_root);
		btrfs_set_disk_key_type(&disk_key, BTRFS_TREE_BLOCK_REF_KEY);
		btrfs_set_item_key(buf, &disk_key, nritems);
		btrfs_set_item_offset(buf, btrfs_item_nr(nritems),
				      itemoff);
		btrfs_set_item_size(buf, btrfs_item_nr(nritems), 0);
		nritems++;
	}
	btrfs_set_header_bytenr(buf, blocks[2]);
	btrfs_set_header_owner(buf, BTRFS_EXTENT_TREE_OBJECTID);
	btrfs_set_header_nritems(buf, nritems);
	csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
	ret = pwrite(fd, buf->data, leafsize, blocks[2]);
	if (ret != leafsize) {
		ret = (ret < 0 ? -errno : -EIO);
		goto out;
	}

	/* create the chunk tree */
	memset(buf->data+sizeof(struct btrfs_header), 0,
		leafsize-sizeof(struct btrfs_header));
	nritems = 0;
	item_size = sizeof(*dev_item);
	itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) - item_size;

	/* first device 1 (there is no device 0) */
	btrfs_set_disk_key_objectid(&disk_key, BTRFS_DEV_ITEMS_OBJECTID);
	btrfs_set_disk_key_offset(&disk_key, 1);
	btrfs_set_disk_key_type(&disk_key, BTRFS_DEV_ITEM_KEY);
	btrfs_set_item_key(buf, &disk_key, nritems);
	btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff);
	btrfs_set_item_size(buf, btrfs_item_nr(nritems), item_size);

	dev_item = btrfs_item_ptr(buf, nritems, struct btrfs_dev_item);
	btrfs_set_device_id(buf, dev_item, 1);
	btrfs_set_device_generation(buf, dev_item, 0);
	btrfs_set_device_total_bytes(buf, dev_item, num_bytes);
	btrfs_set_device_bytes_used(buf, dev_item,
				    BTRFS_MKFS_SYSTEM_GROUP_SIZE);
	btrfs_set_device_io_align(buf, dev_item, sectorsize);
	btrfs_set_device_io_width(buf, dev_item, sectorsize);
	btrfs_set_device_sector_size(buf, dev_item, sectorsize);
	btrfs_set_device_type(buf, dev_item, 0);

	write_extent_buffer(buf, super.dev_item.uuid,
			    (unsigned long)btrfs_device_uuid(dev_item),
			    BTRFS_UUID_SIZE);
	write_extent_buffer(buf, super.fsid,
			    (unsigned long)btrfs_device_fsid(dev_item),
			    BTRFS_UUID_SIZE);
	read_extent_buffer(buf, &super.dev_item, (unsigned long)dev_item,
			   sizeof(*dev_item));

	nritems++;
	item_size = btrfs_chunk_item_size(1);
	itemoff = itemoff - item_size;

	/* then we have chunk 0 */
	btrfs_set_disk_key_objectid(&disk_key, BTRFS_FIRST_CHUNK_TREE_OBJECTID);
	btrfs_set_disk_key_offset(&disk_key, 0);
	btrfs_set_disk_key_type(&disk_key, BTRFS_CHUNK_ITEM_KEY);
	btrfs_set_item_key(buf, &disk_key, nritems);
	btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff);
	btrfs_set_item_size(buf, btrfs_item_nr(nritems), item_size);

	chunk = btrfs_item_ptr(buf, nritems, struct btrfs_chunk);
	btrfs_set_chunk_length(buf, chunk, BTRFS_MKFS_SYSTEM_GROUP_SIZE);
	btrfs_set_chunk_owner(buf, chunk, BTRFS_EXTENT_TREE_OBJECTID);
	btrfs_set_chunk_stripe_len(buf, chunk, 64 * 1024);
	btrfs_set_chunk_type(buf, chunk, BTRFS_BLOCK_GROUP_SYSTEM);
	btrfs_set_chunk_io_align(buf, chunk, sectorsize);
	btrfs_set_chunk_io_width(buf, chunk, sectorsize);
	btrfs_set_chunk_sector_size(buf, chunk, sectorsize);
	btrfs_set_chunk_num_stripes(buf, chunk, 1);
	btrfs_set_stripe_devid_nr(buf, chunk, 0, 1);
	btrfs_set_stripe_offset_nr(buf, chunk, 0, 0);
	nritems++;

	write_extent_buffer(buf, super.dev_item.uuid,
			    (unsigned long)btrfs_stripe_dev_uuid(&chunk->stripe),
			    BTRFS_UUID_SIZE);

	/* copy the key for the chunk to the system array */
	ptr = super.sys_chunk_array;
	array_size = sizeof(disk_key);

	memcpy(ptr, &disk_key, sizeof(disk_key));
	ptr += sizeof(disk_key);

	/* copy the chunk to the system array */
	read_extent_buffer(buf, ptr, (unsigned long)chunk, item_size);
	array_size += item_size;
	ptr += item_size;
	btrfs_set_super_sys_array_size(&super, array_size);

	btrfs_set_header_bytenr(buf, blocks[3]);
	btrfs_set_header_owner(buf, BTRFS_CHUNK_TREE_OBJECTID);
	btrfs_set_header_nritems(buf, nritems);
	csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
	ret = pwrite(fd, buf->data, leafsize, blocks[3]);
	if (ret != leafsize) {
		ret = (ret < 0 ? -errno : -EIO);
		goto out;
	}

	/* create the device tree */
	memset(buf->data+sizeof(struct btrfs_header), 0,
		leafsize-sizeof(struct btrfs_header));
	nritems = 0;
	itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) -
		sizeof(struct btrfs_dev_extent);

	btrfs_set_disk_key_objectid(&disk_key, 1);
	btrfs_set_disk_key_offset(&disk_key, 0);
	btrfs_set_disk_key_type(&disk_key, BTRFS_DEV_EXTENT_KEY);
	btrfs_set_item_key(buf, &disk_key, nritems);
	btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff);
	btrfs_set_item_size(buf, btrfs_item_nr(nritems),
			    sizeof(struct btrfs_dev_extent));
	dev_extent = btrfs_item_ptr(buf, nritems, struct btrfs_dev_extent);
	btrfs_set_dev_extent_chunk_tree(buf, dev_extent,
					BTRFS_CHUNK_TREE_OBJECTID);
	btrfs_set_dev_extent_chunk_objectid(buf, dev_extent,
					BTRFS_FIRST_CHUNK_TREE_OBJECTID);
	btrfs_set_dev_extent_chunk_offset(buf, dev_extent, 0);

	write_extent_buffer(buf, chunk_tree_uuid,
		    (unsigned long)btrfs_dev_extent_chunk_tree_uuid(dev_extent),
		    BTRFS_UUID_SIZE);

	btrfs_set_dev_extent_length(buf, dev_extent,
				    BTRFS_MKFS_SYSTEM_GROUP_SIZE);
	nritems++;

	btrfs_set_header_bytenr(buf, blocks[4]);
	btrfs_set_header_owner(buf, BTRFS_DEV_TREE_OBJECTID);
	btrfs_set_header_nritems(buf, nritems);
	csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
	ret = pwrite(fd, buf->data, leafsize, blocks[4]);
	if (ret != leafsize) {
		ret = (ret < 0 ? -errno : -EIO);
		goto out;
	}

	/* create the FS root */
	memset(buf->data+sizeof(struct btrfs_header), 0,
		leafsize-sizeof(struct btrfs_header));
	btrfs_set_header_bytenr(buf, blocks[5]);
	btrfs_set_header_owner(buf, BTRFS_FS_TREE_OBJECTID);
	btrfs_set_header_nritems(buf, 0);
	csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
	ret = pwrite(fd, buf->data, leafsize, blocks[5]);
	if (ret != leafsize) {
		ret = (ret < 0 ? -errno : -EIO);
		goto out;
	}
	/* finally create the csum root */
	memset(buf->data+sizeof(struct btrfs_header), 0,
		leafsize-sizeof(struct btrfs_header));
	btrfs_set_header_bytenr(buf, blocks[6]);
	btrfs_set_header_owner(buf, BTRFS_CSUM_TREE_OBJECTID);
	btrfs_set_header_nritems(buf, 0);
	csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
	ret = pwrite(fd, buf->data, leafsize, blocks[6]);
	if (ret != leafsize) {
		ret = (ret < 0 ? -errno : -EIO);
		goto out;
	}

	/* and write out the super block */
	BUG_ON(sizeof(super) > sectorsize);
	memset(buf->data, 0, sectorsize);
	memcpy(buf->data, &super, sizeof(super));
	buf->len = sectorsize;
	csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
	ret = pwrite(fd, buf->data, sectorsize, blocks[0]);
	if (ret != sectorsize) {
		ret = (ret < 0 ? -errno : -EIO);
		goto out;
	}

	ret = 0;

out:
	free(buf);
	return ret;
}
示例#22
0
void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *eb)
{
	struct btrfs_item *item;
	struct btrfs_disk_key disk_key;
	u32 i;
	u32 nr;

	nr = btrfs_header_nritems(eb);

	printf("leaf %llu items %d free space %d generation %llu owner %llu\n",
		(unsigned long long)btrfs_header_bytenr(eb), nr,
		btrfs_leaf_free_space(root, eb),
		(unsigned long long)btrfs_header_generation(eb),
		(unsigned long long)btrfs_header_owner(eb));
	print_uuids(eb);
	fflush(stdout);

	for (i = 0; i < nr; i++) {
		u32 item_size;
		void *ptr;
		u64 objectid;
		u32 type;
		u64 offset;
		char flags_str[256];
		char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
		u8 uuid[BTRFS_UUID_SIZE];

		item = btrfs_item_nr(i);
		item_size = btrfs_item_size(eb, item);
		/* Untyped extraction of slot from btrfs_item_ptr */
		ptr = btrfs_item_ptr(eb, i, void*);

		btrfs_item_key(eb, &disk_key, i);
		objectid = btrfs_disk_key_objectid(&disk_key);
		type = btrfs_disk_key_type(&disk_key);
		offset = btrfs_disk_key_offset(&disk_key);

		printf("\titem %d ", i);
		btrfs_print_key(&disk_key);
		printf(" itemoff %d itemsize %d\n",
			btrfs_item_offset(eb, item),
			btrfs_item_size(eb, item));

		if (type == 0 && objectid == BTRFS_FREE_SPACE_OBJECTID)
			print_free_space_header(eb, i);

		switch (type) {
		case BTRFS_INODE_ITEM_KEY:
			print_inode_item(eb, ptr);
			break;
		case BTRFS_INODE_REF_KEY:
			print_inode_ref_item(eb, item_size, ptr);
			break;
		case BTRFS_INODE_EXTREF_KEY:
			print_inode_extref_item(eb, item_size, ptr);
			break;
		case BTRFS_DIR_ITEM_KEY:
		case BTRFS_DIR_INDEX_KEY:
		case BTRFS_XATTR_ITEM_KEY:
			print_dir_item(eb, item_size, ptr);
			break;
		case BTRFS_DIR_LOG_INDEX_KEY:
		case BTRFS_DIR_LOG_ITEM_KEY: {
			struct btrfs_dir_log_item *dlog;

			dlog = btrfs_item_ptr(eb, i, struct btrfs_dir_log_item);
			printf("\t\tdir log end %Lu\n",
			       (unsigned long long)btrfs_dir_log_end(eb, dlog));
			break;
			}
		case BTRFS_ORPHAN_ITEM_KEY:
			printf("\t\torphan item\n");
			break;
		case BTRFS_ROOT_ITEM_KEY:
			print_root(eb, i);
			break;
		case BTRFS_ROOT_REF_KEY:
			print_root_ref(eb, i, "ref");
			break;
		case BTRFS_ROOT_BACKREF_KEY:
			print_root_ref(eb, i, "backref");
			break;
		case BTRFS_EXTENT_ITEM_KEY:
			print_extent_item(eb, i, 0);
			break;
		case BTRFS_METADATA_ITEM_KEY:
			print_extent_item(eb, i, 1);
			break;
		case BTRFS_TREE_BLOCK_REF_KEY:
			printf("\t\ttree block backref\n");
			break;
		case BTRFS_SHARED_BLOCK_REF_KEY:
			printf("\t\tshared block backref\n");
			break;
		case BTRFS_EXTENT_DATA_REF_KEY: {
			struct btrfs_extent_data_ref *dref;

			dref = btrfs_item_ptr(eb, i, struct btrfs_extent_data_ref);
			printf("\t\textent data backref root %llu "
			       "objectid %llu offset %llu count %u\n",
			       (unsigned long long)btrfs_extent_data_ref_root(eb, dref),
			       (unsigned long long)btrfs_extent_data_ref_objectid(eb, dref),
			       (unsigned long long)btrfs_extent_data_ref_offset(eb, dref),
			       btrfs_extent_data_ref_count(eb, dref));
			break;
			}
		case BTRFS_SHARED_DATA_REF_KEY: {
			struct btrfs_shared_data_ref *sref;
			sref = btrfs_item_ptr(eb, i, struct btrfs_shared_data_ref);
			printf("\t\tshared data backref count %u\n",
			       btrfs_shared_data_ref_count(eb, sref));
			break;
			}
		case BTRFS_EXTENT_REF_V0_KEY:
#ifdef BTRFS_COMPAT_EXTENT_TREE_V0
			print_extent_ref_v0(eb, i);
#else
			BUG();
#endif
			break;
		case BTRFS_CSUM_ITEM_KEY:
			printf("\t\tcsum item\n");
			break;
		case BTRFS_EXTENT_CSUM_KEY:
			printf("\t\textent csum item\n");
			break;
		case BTRFS_EXTENT_DATA_KEY:
			print_file_extent_item(eb, item, i, ptr);
			break;
		case BTRFS_BLOCK_GROUP_ITEM_KEY: {
			struct btrfs_block_group_item bg_item;

			read_extent_buffer(eb, &bg_item, (unsigned long)ptr,
					   sizeof(bg_item));
			memset(flags_str, 0, sizeof(flags_str));
			bg_flags_to_str(btrfs_block_group_flags(&bg_item),
					flags_str);
			printf("\t\tblock group used %llu chunk_objectid %llu flags %s\n",
			       (unsigned long long)btrfs_block_group_used(&bg_item),
			       (unsigned long long)btrfs_block_group_chunk_objectid(&bg_item),
			       flags_str);
			break;
			}
		case BTRFS_FREE_SPACE_INFO_KEY: {
			struct btrfs_free_space_info *free_info;

			free_info = btrfs_item_ptr(eb, i, struct btrfs_free_space_info);
			printf("\t\tfree space info extent count %u flags %u\n",
			       (unsigned)btrfs_free_space_extent_count(eb, free_info),
			       (unsigned)btrfs_free_space_flags(eb, free_info));
			break;
			}
		case BTRFS_FREE_SPACE_EXTENT_KEY:
			printf("\t\tfree space extent\n");
			break;
		case BTRFS_FREE_SPACE_BITMAP_KEY:
			printf("\t\tfree space bitmap\n");
			break;
		case BTRFS_CHUNK_ITEM_KEY:
			print_chunk(eb, ptr);
			break;
		case BTRFS_DEV_ITEM_KEY:
			print_dev_item(eb, ptr);
			break;
		case BTRFS_DEV_EXTENT_KEY: {
			struct btrfs_dev_extent *dev_extent;

			dev_extent = btrfs_item_ptr(eb, i,
						    struct btrfs_dev_extent);
			read_extent_buffer(eb, uuid,
				(unsigned long)btrfs_dev_extent_chunk_tree_uuid(dev_extent),
				BTRFS_UUID_SIZE);
			uuid_unparse(uuid, uuid_str);
			printf("\t\tdev extent chunk_tree %llu\n"
			       "\t\tchunk_objectid %llu chunk_offset %llu "
			       "length %llu\n"
			       "\t\tchunk_tree_uuid %s\n",
			       (unsigned long long)
			       btrfs_dev_extent_chunk_tree(eb, dev_extent),
			       (unsigned long long)
			       btrfs_dev_extent_chunk_objectid(eb, dev_extent),
			       (unsigned long long)
			       btrfs_dev_extent_chunk_offset(eb, dev_extent),
			       (unsigned long long)
			       btrfs_dev_extent_length(eb, dev_extent),
			       uuid_str);
			break;
			}
		case BTRFS_QGROUP_STATUS_KEY: {
			struct btrfs_qgroup_status_item *qg_status;

			qg_status = btrfs_item_ptr(eb, i,
					struct btrfs_qgroup_status_item);
			memset(flags_str, 0, sizeof(flags_str));
			qgroup_flags_to_str(btrfs_qgroup_status_flags(eb, qg_status),
					flags_str);
			printf("\t\tversion %llu generation %llu flags %s "
				"scan %lld\n",
				(unsigned long long)
				btrfs_qgroup_status_version(eb, qg_status),
				(unsigned long long)
				btrfs_qgroup_status_generation(eb, qg_status),
				flags_str,
				(unsigned long long)
				btrfs_qgroup_status_rescan(eb, qg_status));
			break;
			}
		case BTRFS_QGROUP_RELATION_KEY:
			break;
		case BTRFS_QGROUP_INFO_KEY: {
			struct btrfs_qgroup_info_item *qg_info;

			qg_info = btrfs_item_ptr(eb, i,
						 struct btrfs_qgroup_info_item);
			printf("\t\tgeneration %llu\n"
			     "\t\treferenced %llu referenced_compressed %llu\n"
			     "\t\texclusive %llu exclusive_compressed %llu\n",
			       (unsigned long long)
			       btrfs_qgroup_info_generation(eb, qg_info),
			       (unsigned long long)
			       btrfs_qgroup_info_referenced(eb, qg_info),
			       (unsigned long long)
			       btrfs_qgroup_info_referenced_compressed(eb,
								       qg_info),
			       (unsigned long long)
			       btrfs_qgroup_info_exclusive(eb, qg_info),
			       (unsigned long long)
			       btrfs_qgroup_info_exclusive_compressed(eb,
								      qg_info));
			break;
			}
		case BTRFS_QGROUP_LIMIT_KEY: {
			struct btrfs_qgroup_limit_item *qg_limit;

			qg_limit = btrfs_item_ptr(eb, i,
					 struct btrfs_qgroup_limit_item);
			printf("\t\tflags %llx\n"
			     "\t\tmax_referenced %lld max_exclusive %lld\n"
			     "\t\trsv_referenced %lld rsv_exclusive %lld\n",
			       (unsigned long long)
			       btrfs_qgroup_limit_flags(eb, qg_limit),
			       (long long)
			       btrfs_qgroup_limit_max_referenced(eb, qg_limit),
			       (long long)
			       btrfs_qgroup_limit_max_exclusive(eb, qg_limit),
			       (long long)
			       btrfs_qgroup_limit_rsv_referenced(eb, qg_limit),
			       (long long)
			       btrfs_qgroup_limit_rsv_exclusive(eb, qg_limit));
			break;
			}
		case BTRFS_UUID_KEY_SUBVOL:
		case BTRFS_UUID_KEY_RECEIVED_SUBVOL:
			print_uuid_item(eb, btrfs_item_ptr_offset(eb, i),
					btrfs_item_size_nr(eb, i));
			break;
		case BTRFS_STRING_ITEM_KEY: {
			const char *str = eb->data + btrfs_item_ptr_offset(eb, i);

			printf("\t\titem data %.*s\n", item_size, str);
			break;
			}
		case BTRFS_PERSISTENT_ITEM_KEY:
			printf("\t\tpersistent item objectid ");
			print_objectid(stdout, objectid, BTRFS_PERSISTENT_ITEM_KEY);
			printf(" offset %llu\n", (unsigned long long)offset);
			switch (objectid) {
			case BTRFS_DEV_STATS_OBJECTID:
				print_dev_stats(eb, ptr, item_size);
				break;
			default:
				printf("\t\tunknown persistent item objectid %llu\n",
						objectid);
			}
			break;
		case BTRFS_TEMPORARY_ITEM_KEY:
			printf("\t\ttemporary item objectid ");
			print_objectid(stdout, objectid, BTRFS_TEMPORARY_ITEM_KEY);
			printf(" offset %llu\n", (unsigned long long)offset);
			switch (objectid) {
			case BTRFS_BALANCE_OBJECTID:
				print_balance_item(eb, ptr);
				break;
			default:
				printf("\t\tunknown temporary item objectid %llu\n",
						objectid);
			}
			break;
		};
		fflush(stdout);
	}
}
示例#23
0
文件: print-tree.c 项目: 020gzh/linux
void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
{
	int i;
	u32 type, nr;
	struct btrfs_item *item;
	struct btrfs_root_item *ri;
	struct btrfs_dir_item *di;
	struct btrfs_inode_item *ii;
	struct btrfs_block_group_item *bi;
	struct btrfs_file_extent_item *fi;
	struct btrfs_extent_data_ref *dref;
	struct btrfs_shared_data_ref *sref;
	struct btrfs_dev_extent *dev_extent;
	struct btrfs_key key;
	struct btrfs_key found_key;

	if (!l)
		return;

	nr = btrfs_header_nritems(l);

	btrfs_info(root->fs_info, "leaf %llu total ptrs %d free space %d",
		   btrfs_header_bytenr(l), nr, btrfs_leaf_free_space(root, l));
	for (i = 0 ; i < nr ; i++) {
		item = btrfs_item_nr(i);
		btrfs_item_key_to_cpu(l, &key, i);
		type = key.type;
		printk(KERN_INFO "\titem %d key (%llu %u %llu) itemoff %d "
		       "itemsize %d\n",
			i, key.objectid, type, key.offset,
			btrfs_item_offset(l, item), btrfs_item_size(l, item));
		switch (type) {
		case BTRFS_INODE_ITEM_KEY:
			ii = btrfs_item_ptr(l, i, struct btrfs_inode_item);
			printk(KERN_INFO "\t\tinode generation %llu size %llu "
			       "mode %o\n",
			       btrfs_inode_generation(l, ii),
			       btrfs_inode_size(l, ii),
			       btrfs_inode_mode(l, ii));
			break;
		case BTRFS_DIR_ITEM_KEY:
			di = btrfs_item_ptr(l, i, struct btrfs_dir_item);
			btrfs_dir_item_key_to_cpu(l, di, &found_key);
			printk(KERN_INFO "\t\tdir oid %llu type %u\n",
				found_key.objectid,
				btrfs_dir_type(l, di));
			break;
		case BTRFS_ROOT_ITEM_KEY:
			ri = btrfs_item_ptr(l, i, struct btrfs_root_item);
			printk(KERN_INFO "\t\troot data bytenr %llu refs %u\n",
				btrfs_disk_root_bytenr(l, ri),
				btrfs_disk_root_refs(l, ri));
			break;
		case BTRFS_EXTENT_ITEM_KEY:
		case BTRFS_METADATA_ITEM_KEY:
			print_extent_item(l, i, type);
			break;
		case BTRFS_TREE_BLOCK_REF_KEY:
			printk(KERN_INFO "\t\ttree block backref\n");
			break;
		case BTRFS_SHARED_BLOCK_REF_KEY:
			printk(KERN_INFO "\t\tshared block backref\n");
			break;
		case BTRFS_EXTENT_DATA_REF_KEY:
			dref = btrfs_item_ptr(l, i,
					      struct btrfs_extent_data_ref);
			print_extent_data_ref(l, dref);
			break;
		case BTRFS_SHARED_DATA_REF_KEY:
			sref = btrfs_item_ptr(l, i,
					      struct btrfs_shared_data_ref);
			printk(KERN_INFO "\t\tshared data backref count %u\n",
			       btrfs_shared_data_ref_count(l, sref));
			break;
		case BTRFS_EXTENT_DATA_KEY:
			fi = btrfs_item_ptr(l, i,
					    struct btrfs_file_extent_item);
			if (btrfs_file_extent_type(l, fi) ==
			    BTRFS_FILE_EXTENT_INLINE) {
				printk(KERN_INFO "\t\tinline extent data "
				       "size %u\n",
				       btrfs_file_extent_inline_len(l, i, fi));
				break;
			}
			printk(KERN_INFO "\t\textent data disk bytenr %llu "
			       "nr %llu\n",
			       btrfs_file_extent_disk_bytenr(l, fi),
			       btrfs_file_extent_disk_num_bytes(l, fi));
			printk(KERN_INFO "\t\textent data offset %llu "
			       "nr %llu ram %llu\n",
			       btrfs_file_extent_offset(l, fi),
			       btrfs_file_extent_num_bytes(l, fi),
			       btrfs_file_extent_ram_bytes(l, fi));
			break;
		case BTRFS_EXTENT_REF_V0_KEY:
#ifdef BTRFS_COMPAT_EXTENT_TREE_V0
			print_extent_ref_v0(l, i);
#else
			BUG();
#endif
			break;
		case BTRFS_BLOCK_GROUP_ITEM_KEY:
			bi = btrfs_item_ptr(l, i,
					    struct btrfs_block_group_item);
			printk(KERN_INFO "\t\tblock group used %llu\n",
			       btrfs_disk_block_group_used(l, bi));
			break;
		case BTRFS_CHUNK_ITEM_KEY:
			print_chunk(l, btrfs_item_ptr(l, i,
						      struct btrfs_chunk));
			break;
		case BTRFS_DEV_ITEM_KEY:
			print_dev_item(l, btrfs_item_ptr(l, i,
					struct btrfs_dev_item));
			break;
		case BTRFS_DEV_EXTENT_KEY:
			dev_extent = btrfs_item_ptr(l, i,
						    struct btrfs_dev_extent);
			printk(KERN_INFO "\t\tdev extent chunk_tree %llu\n"
			       "\t\tchunk objectid %llu chunk offset %llu "
			       "length %llu\n",
			       btrfs_dev_extent_chunk_tree(l, dev_extent),
			       btrfs_dev_extent_chunk_objectid(l, dev_extent),
			       btrfs_dev_extent_chunk_offset(l, dev_extent),
			       btrfs_dev_extent_length(l, dev_extent));
			break;
		case BTRFS_PERSISTENT_ITEM_KEY:
			printk(KERN_INFO "\t\tpersistent item objectid %llu offset %llu\n",
					key.objectid, key.offset);
			switch (key.objectid) {
			case BTRFS_DEV_STATS_OBJECTID:
				printk(KERN_INFO "\t\tdevice stats\n");
				break;
			default:
				printk(KERN_INFO "\t\tunknown persistent item\n");
			}
			break;
		case BTRFS_TEMPORARY_ITEM_KEY:
			printk(KERN_INFO "\t\ttemporary item objectid %llu offset %llu\n",
					key.objectid, key.offset);
			switch (key.objectid) {
			case BTRFS_BALANCE_OBJECTID:
				printk(KERN_INFO "\t\tbalance status\n");
				break;
			default:
				printk(KERN_INFO "\t\tunknown temporary item\n");
			}
			break;
		case BTRFS_DEV_REPLACE_KEY:
			printk(KERN_INFO "\t\tdev replace\n");
			break;
		case BTRFS_UUID_KEY_SUBVOL:
		case BTRFS_UUID_KEY_RECEIVED_SUBVOL:
			print_uuid_item(l, btrfs_item_ptr_offset(l, i),
					btrfs_item_size_nr(l, i));
			break;
		};
	}
}
示例#24
0
int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid,
			  u64 start_off, struct btrfs_path *path,
			  struct btrfs_inode_extref **ret_extref,
			  u64 *found_off)
{
	int ret, slot;
	struct btrfs_key key;
	struct btrfs_key found_key;
	struct btrfs_inode_extref *extref;
	struct extent_buffer *leaf;
	unsigned long ptr;

	key.objectid = inode_objectid;
	btrfs_set_key_type(&key, BTRFS_INODE_EXTREF_KEY);
	key.offset = start_off;

	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
	if (ret < 0)
		return ret;

	while (1) {
		leaf = path->nodes[0];
		slot = path->slots[0];
		if (slot >= btrfs_header_nritems(leaf)) {
			/*
			 * If the item at offset is not found,
			 * btrfs_search_slot will point us to the slot
			 * where it should be inserted. In our case
			 * that will be the slot directly before the
			 * next INODE_REF_KEY_V2 item. In the case
			 * that we're pointing to the last slot in a
			 * leaf, we must move one leaf over.
			 */
			ret = btrfs_next_leaf(root, path);
			if (ret) {
				if (ret >= 1)
					ret = -ENOENT;
				break;
			}
			continue;
		}

		btrfs_item_key_to_cpu(leaf, &found_key, slot);

		/*
		 * Check that we're still looking at an extended ref key for
		 * this particular objectid. If we have different
		 * objectid or type then there are no more to be found
		 * in the tree and we can exit.
		 */
		ret = -ENOENT;
		if (found_key.objectid != inode_objectid)
			break;
		if (btrfs_key_type(&found_key) != BTRFS_INODE_EXTREF_KEY)
			break;

		ret = 0;
		ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
		extref = (struct btrfs_inode_extref *)ptr;
		*ret_extref = extref;
		if (found_off)
			*found_off = found_key.offset;
		break;
	}

	return ret;
}
示例#25
0
void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
{
	int i;
	char *str;
	struct btrfs_item *item;
	struct btrfs_root_item *ri;
	struct btrfs_dir_item *di;
	struct btrfs_inode_item *ii;
	struct btrfs_file_extent_item *fi;
	struct btrfs_block_group_item *bi;
	struct btrfs_extent_data_ref *dref;
	struct btrfs_shared_data_ref *sref;
	struct btrfs_inode_ref *iref;
	struct btrfs_dev_extent *dev_extent;
	struct btrfs_disk_key disk_key;
	struct btrfs_root_item root_item;
	struct btrfs_block_group_item bg_item;
	struct btrfs_dir_log_item *dlog;
	u32 nr = btrfs_header_nritems(l);
	u32 type;

	printf("leaf %llu items %d free space %d generation %llu owner %llu\n",
		(unsigned long long)btrfs_header_bytenr(l), nr,
		btrfs_leaf_free_space(root, l),
		(unsigned long long)btrfs_header_generation(l),
		(unsigned long long)btrfs_header_owner(l));
	print_uuids(l);
	fflush(stdout);
	for (i = 0 ; i < nr ; i++) {
		item = btrfs_item_nr(l, i);
		btrfs_item_key(l, &disk_key, i);
		type = btrfs_disk_key_type(&disk_key);
		printf("\titem %d ", i);
		btrfs_print_key(&disk_key);
		printf(" itemoff %d itemsize %d\n",
			btrfs_item_offset(l, item),
			btrfs_item_size(l, item));
		switch (type) {
		case BTRFS_INODE_ITEM_KEY:
			ii = btrfs_item_ptr(l, i, struct btrfs_inode_item);
			printf("\t\tinode generation %llu size %llu block group %llu mode %o links %u\n",
			       (unsigned long long)btrfs_inode_generation(l, ii),
			       (unsigned long long)btrfs_inode_size(l, ii),
			       (unsigned long long)btrfs_inode_block_group(l,ii),
			       btrfs_inode_mode(l, ii),
			       btrfs_inode_nlink(l, ii));
			break;
		case BTRFS_INODE_REF_KEY:
			iref = btrfs_item_ptr(l, i, struct btrfs_inode_ref);
			print_inode_ref_item(l, item, iref);
			break;
		case BTRFS_DIR_ITEM_KEY:
		case BTRFS_DIR_INDEX_KEY:
		case BTRFS_XATTR_ITEM_KEY:
			di = btrfs_item_ptr(l, i, struct btrfs_dir_item);
			print_dir_item(l, item, di);
			break;
		case BTRFS_DIR_LOG_INDEX_KEY:
		case BTRFS_DIR_LOG_ITEM_KEY:
			dlog = btrfs_item_ptr(l, i, struct btrfs_dir_log_item);
			printf("\t\tdir log end %Lu\n",
			       (unsigned long long)btrfs_dir_log_end(l, dlog));
		       break;
		case BTRFS_ORPHAN_ITEM_KEY:
			printf("\t\torphan item\n");
			break;
		case BTRFS_ROOT_ITEM_KEY:
			ri = btrfs_item_ptr(l, i, struct btrfs_root_item);
			read_extent_buffer(l, &root_item, (unsigned long)ri, sizeof(root_item));
			printf("\t\troot data bytenr %llu level %d dirid %llu refs %u gen %llu\n",
				(unsigned long long)btrfs_root_bytenr(&root_item),
				btrfs_root_level(&root_item),
				(unsigned long long)btrfs_root_dirid(&root_item),
				btrfs_root_refs(&root_item),
				(unsigned long long)btrfs_root_generation(&root_item));
			if (btrfs_root_refs(&root_item) == 0) {
				struct btrfs_key drop_key;
				btrfs_disk_key_to_cpu(&drop_key,
						      &root_item.drop_progress);
				printf("\t\tdrop ");
				btrfs_print_key(&root_item.drop_progress);
				printf(" level %d\n", root_item.drop_level);
			}
			break;
		case BTRFS_ROOT_REF_KEY:
			print_root_ref(l, i, "ref");
			break;
		case BTRFS_ROOT_BACKREF_KEY:
			print_root_ref(l, i, "backref");
			break;
		case BTRFS_EXTENT_ITEM_KEY:
			print_extent_item(l, i);
			break;
		case BTRFS_TREE_BLOCK_REF_KEY:
			printf("\t\ttree block backref\n");
			break;
		case BTRFS_SHARED_BLOCK_REF_KEY:
			printf("\t\tshared block backref\n");
			break;
		case BTRFS_EXTENT_DATA_REF_KEY:
			dref = btrfs_item_ptr(l, i, struct btrfs_extent_data_ref);
			printf("\t\textent data backref root %llu "
			       "objectid %llu offset %llu count %u\n",
			       (unsigned long long)btrfs_extent_data_ref_root(l, dref),
			       (unsigned long long)btrfs_extent_data_ref_objectid(l, dref),
			       (unsigned long long)btrfs_extent_data_ref_offset(l, dref),
			       btrfs_extent_data_ref_count(l, dref));
			break;
		case BTRFS_SHARED_DATA_REF_KEY:
			sref = btrfs_item_ptr(l, i, struct btrfs_shared_data_ref);
			printf("\t\tshared data backref count %u\n",
			       btrfs_shared_data_ref_count(l, sref));
			break;
		case BTRFS_EXTENT_REF_V0_KEY:
#ifdef BTRFS_COMPAT_EXTENT_TREE_V0
			print_extent_ref_v0(l, i);
#else
			BUG();
#endif
			break;
		case BTRFS_CSUM_ITEM_KEY:
			printf("\t\tcsum item\n");
			break;
		case BTRFS_EXTENT_CSUM_KEY:
			printf("\t\textent csum item\n");
			break;
		case BTRFS_EXTENT_DATA_KEY:
			fi = btrfs_item_ptr(l, i,
					    struct btrfs_file_extent_item);
			print_file_extent_item(l, item, fi);
			break;
		case BTRFS_BLOCK_GROUP_ITEM_KEY:
			bi = btrfs_item_ptr(l, i,
					    struct btrfs_block_group_item);
			read_extent_buffer(l, &bg_item, (unsigned long)bi,
					   sizeof(bg_item));
			printf("\t\tblock group used %llu chunk_objectid %llu flags %llu\n",
			       (unsigned long long)btrfs_block_group_used(&bg_item),
			       (unsigned long long)btrfs_block_group_chunk_objectid(&bg_item),
			       (unsigned long long)btrfs_block_group_flags(&bg_item));
			break;
		case BTRFS_CHUNK_ITEM_KEY:
			print_chunk(l, btrfs_item_ptr(l, i, struct btrfs_chunk));
			break;
		case BTRFS_DEV_ITEM_KEY:
			print_dev_item(l, btrfs_item_ptr(l, i,
					struct btrfs_dev_item));
			break;
		case BTRFS_DEV_EXTENT_KEY:
			dev_extent = btrfs_item_ptr(l, i,
						    struct btrfs_dev_extent);
			printf("\t\tdev extent chunk_tree %llu\n"
			       "\t\tchunk objectid %llu chunk offset %llu "
			       "length %llu\n",
			       (unsigned long long)
			       btrfs_dev_extent_chunk_tree(l, dev_extent),
			       (unsigned long long)
			       btrfs_dev_extent_chunk_objectid(l, dev_extent),
			       (unsigned long long)
			       btrfs_dev_extent_chunk_offset(l, dev_extent),
			       (unsigned long long)
			       btrfs_dev_extent_length(l, dev_extent));
			break;
		case BTRFS_STRING_ITEM_KEY:
			/* dirty, but it's simple */
			str = l->data + btrfs_item_ptr_offset(l, i);
			printf("\t\titem data %.*s\n", btrfs_item_size(l, item), str);
			break;
		};
		fflush(stdout);
	}
}
示例#26
0
static int iterate_inode_extrefs(u64 inum, struct btrfs_root *fs_root,
				 struct btrfs_path *path,
				 iterate_irefs_t *iterate, void *ctx)
{
	int ret;
	int slot;
	u64 offset = 0;
	u64 parent;
	int found = 0;
	struct extent_buffer *eb;
	struct btrfs_inode_extref *extref;
	struct extent_buffer *leaf;
	u32 item_size;
	u32 cur_offset;
	unsigned long ptr;

	while (1) {
		ret = btrfs_find_one_extref(fs_root, inum, offset, path, &extref,
					    &offset);
		if (ret < 0)
			break;
		if (ret) {
			ret = found ? 0 : -ENOENT;
			break;
		}
		++found;

		slot = path->slots[0];
		eb = btrfs_clone_extent_buffer(path->nodes[0]);
		if (!eb) {
			ret = -ENOMEM;
			break;
		}
		extent_buffer_get(eb);

		btrfs_release_path(path);

		leaf = path->nodes[0];
		item_size = btrfs_item_size_nr(leaf, slot);
		ptr = btrfs_item_ptr_offset(leaf, slot);
		cur_offset = 0;

		while (cur_offset < item_size) {
			u32 name_len;

			extref = (struct btrfs_inode_extref *)(ptr + cur_offset);
			parent = btrfs_inode_extref_parent(eb, extref);
			name_len = btrfs_inode_extref_name_len(eb, extref);
			ret = iterate(parent, name_len,
				      (unsigned long)&extref->name, eb, ctx);
			if (ret)
				break;

			cur_offset += btrfs_inode_extref_name_len(leaf, extref);
			cur_offset += sizeof(*extref);
		}
		free_extent_buffer(eb);

		offset++;
	}

	btrfs_release_path(path);

	return ret;
}
示例#27
0
文件: file-item.c 项目: ebichu/dd-wrt
/*
 * deletes the csum items from the csum tree for a given
 * range of bytes.
 */
int btrfs_del_csums(struct btrfs_trans_handle *trans,
		    struct btrfs_root *root, u64 bytenr, u64 len)
{
	struct btrfs_path *path;
	struct btrfs_key key;
	u64 end_byte = bytenr + len;
	u64 csum_end;
	struct extent_buffer *leaf;
	int ret;
	u16 csum_size =
		btrfs_super_csum_size(&root->fs_info->super_copy);
	int blocksize = root->sectorsize;

	root = root->fs_info->csum_root;

	path = btrfs_alloc_path();

	while (1) {
		key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
		key.offset = end_byte - 1;
		key.type = BTRFS_EXTENT_CSUM_KEY;

		ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
		if (ret > 0) {
			if (path->slots[0] == 0)
				goto out;
			path->slots[0]--;
		}
		leaf = path->nodes[0];
		btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);

		if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
		    key.type != BTRFS_EXTENT_CSUM_KEY) {
			break;
		}

		if (key.offset >= end_byte)
			break;

		csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size;
		csum_end *= blocksize;
		csum_end += key.offset;

		/* this csum ends before we start, we're done */
		if (csum_end <= bytenr)
			break;

		/* delete the entire item, it is inside our range */
		if (key.offset >= bytenr && csum_end <= end_byte) {
			ret = btrfs_del_item(trans, root, path);
			BUG_ON(ret);
		} else if (key.offset < bytenr && csum_end > end_byte) {
			unsigned long offset;
			unsigned long shift_len;
			unsigned long item_offset;
			/*
			 *        [ bytenr - len ]
			 *     [csum                ]
			 *
			 * Our bytes are in the middle of the csum,
			 * we need to split this item and insert a new one.
			 *
			 * But we can't drop the path because the
			 * csum could change, get removed, extended etc.
			 *
			 * The trick here is the max size of a csum item leaves
			 * enough room in the tree block for a single
			 * item header.  So, we split the item in place,
			 * adding a new header pointing to the existing
			 * bytes.  Then we loop around again and we have
			 * a nicely formed csum item that we can neatly
			 * truncate.
			 */
			offset = (bytenr - key.offset) / blocksize;
			offset *= csum_size;

			shift_len = (len / blocksize) * csum_size;

			item_offset = btrfs_item_ptr_offset(leaf,
							    path->slots[0]);

			memset_extent_buffer(leaf, 0, item_offset + offset,
					     shift_len);
			key.offset = bytenr;

			/*
			 * btrfs_split_item returns -EAGAIN when the
			 * item changed size or key
			 */
			ret = btrfs_split_item(trans, root, path, &key, offset);
			BUG_ON(ret && ret != -EAGAIN);

			key.offset = end_byte - 1;
		} else {
			ret = truncate_one_csum(trans, root, path,
						&key, bytenr, len);
			BUG_ON(ret);
		}
		btrfs_release_path(root, path);
	}
out:
	btrfs_free_path(path);
	return 0;
}
示例#28
0
static int test_btrfs_split_item(u32 sectorsize, u32 nodesize)
{
	struct btrfs_fs_info *fs_info;
	struct btrfs_path *path = NULL;
	struct btrfs_root *root = NULL;
	struct extent_buffer *eb;
	struct btrfs_item *item;
	char *value = "mary had a little lamb";
	char *split1 = "mary had a little";
	char *split2 = " lamb";
	char *split3 = "mary";
	char *split4 = " had a little";
	char buf[32];
	struct btrfs_key key;
	u32 value_len = strlen(value);
	int ret = 0;

	test_msg("Running btrfs_split_item tests\n");

	fs_info = btrfs_alloc_dummy_fs_info();
	if (!fs_info) {
		test_msg("Could not allocate fs_info\n");
		return -ENOMEM;
	}

	root = btrfs_alloc_dummy_root(fs_info, sectorsize, nodesize);
	if (IS_ERR(root)) {
		test_msg("Could not allocate root\n");
		ret = PTR_ERR(root);
		goto out;
	}

	path = btrfs_alloc_path();
	if (!path) {
		test_msg("Could not allocate path\n");
		ret = -ENOMEM;
		goto out;
	}

	path->nodes[0] = eb = alloc_dummy_extent_buffer(NULL, nodesize,
							nodesize);
	if (!eb) {
		test_msg("Could not allocate dummy buffer\n");
		ret = -ENOMEM;
		goto out;
	}
	path->slots[0] = 0;

	key.objectid = 0;
	key.type = BTRFS_EXTENT_CSUM_KEY;
	key.offset = 0;

	setup_items_for_insert(root, path, &key, &value_len, value_len,
			       value_len + sizeof(struct btrfs_item), 1);
	item = btrfs_item_nr(0);
	write_extent_buffer(eb, value, btrfs_item_ptr_offset(eb, 0),
			    value_len);

	key.offset = 3;

	/*
	 * Passing NULL trans here should be safe because we have plenty of
	 * space in this leaf to split the item without having to split the
	 * leaf.
	 */
	ret = btrfs_split_item(NULL, root, path, &key, 17);
	if (ret) {
		test_msg("Split item failed %d\n", ret);
		goto out;
	}

	/*
	 * Read the first slot, it should have the original key and contain only
	 * 'mary had a little'
	 */
	btrfs_item_key_to_cpu(eb, &key, 0);
	if (key.objectid != 0 || key.type != BTRFS_EXTENT_CSUM_KEY ||
	    key.offset != 0) {
		test_msg("Invalid key at slot 0\n");
		ret = -EINVAL;
		goto out;
	}

	item = btrfs_item_nr(0);
	if (btrfs_item_size(eb, item) != strlen(split1)) {
		test_msg("Invalid len in the first split\n");
		ret = -EINVAL;
		goto out;
	}

	read_extent_buffer(eb, buf, btrfs_item_ptr_offset(eb, 0),
			   strlen(split1));
	if (memcmp(buf, split1, strlen(split1))) {
		test_msg("Data in the buffer doesn't match what it should "
			 "in the first split have='%.*s' want '%s'\n",
			 (int)strlen(split1), buf, split1);
		ret = -EINVAL;
		goto out;
	}

	btrfs_item_key_to_cpu(eb, &key, 1);
	if (key.objectid != 0 || key.type != BTRFS_EXTENT_CSUM_KEY ||
	    key.offset != 3) {
		test_msg("Invalid key at slot 1\n");
		ret = -EINVAL;
		goto out;
	}

	item = btrfs_item_nr(1);
	if (btrfs_item_size(eb, item) != strlen(split2)) {
		test_msg("Invalid len in the second split\n");
		ret = -EINVAL;
		goto out;
	}

	read_extent_buffer(eb, buf, btrfs_item_ptr_offset(eb, 1),
			   strlen(split2));
	if (memcmp(buf, split2, strlen(split2))) {
		test_msg("Data in the buffer doesn't match what it should "
			 "in the second split\n");
		ret = -EINVAL;
		goto out;
	}

	key.offset = 1;
	/* Do it again so we test memmoving the other items in the leaf */
	ret = btrfs_split_item(NULL, root, path, &key, 4);
	if (ret) {
		test_msg("Second split item failed %d\n", ret);
		goto out;
	}

	btrfs_item_key_to_cpu(eb, &key, 0);
	if (key.objectid != 0 || key.type != BTRFS_EXTENT_CSUM_KEY ||
	    key.offset != 0) {
		test_msg("Invalid key at slot 0\n");
		ret = -EINVAL;
		goto out;
	}

	item = btrfs_item_nr(0);
	if (btrfs_item_size(eb, item) != strlen(split3)) {
		test_msg("Invalid len in the first split\n");
		ret = -EINVAL;
		goto out;
	}

	read_extent_buffer(eb, buf, btrfs_item_ptr_offset(eb, 0),
			   strlen(split3));
	if (memcmp(buf, split3, strlen(split3))) {
		test_msg("Data in the buffer doesn't match what it should "
			 "in the third split");
		ret = -EINVAL;
		goto out;
	}

	btrfs_item_key_to_cpu(eb, &key, 1);
	if (key.objectid != 0 || key.type != BTRFS_EXTENT_CSUM_KEY ||
	    key.offset != 1) {
		test_msg("Invalid key at slot 1\n");
		ret = -EINVAL;
		goto out;
	}

	item = btrfs_item_nr(1);
	if (btrfs_item_size(eb, item) != strlen(split4)) {
		test_msg("Invalid len in the second split\n");
		ret = -EINVAL;
		goto out;
	}

	read_extent_buffer(eb, buf, btrfs_item_ptr_offset(eb, 1),
			   strlen(split4));
	if (memcmp(buf, split4, strlen(split4))) {
		test_msg("Data in the buffer doesn't match what it should "
			 "in the fourth split\n");
		ret = -EINVAL;
		goto out;
	}

	btrfs_item_key_to_cpu(eb, &key, 2);
	if (key.objectid != 0 || key.type != BTRFS_EXTENT_CSUM_KEY ||
	    key.offset != 3) {
		test_msg("Invalid key at slot 2\n");
		ret = -EINVAL;
		goto out;
	}

	item = btrfs_item_nr(2);
	if (btrfs_item_size(eb, item) != strlen(split2)) {
		test_msg("Invalid len in the second split\n");
		ret = -EINVAL;
		goto out;
	}

	read_extent_buffer(eb, buf, btrfs_item_ptr_offset(eb, 2),
			   strlen(split2));
	if (memcmp(buf, split2, strlen(split2))) {
		test_msg("Data in the buffer doesn't match what it should "
			 "in the last chunk\n");
		ret = -EINVAL;
		goto out;
	}
out:
	btrfs_free_path(path);
	btrfs_free_dummy_root(root);
	btrfs_free_dummy_fs_info(fs_info);
	return ret;
}