Example #1
0
static void print_inode_item(struct extent_buffer *eb,
		struct btrfs_inode_item *ii)
{
	char flags_str[256];

	memset(flags_str, 0, sizeof(flags_str));
	inode_flags_to_str(btrfs_inode_flags(eb, ii), flags_str);
	printf("\t\tinode generation %llu transid %llu size %llu nbytes %llu\n"
	       "\t\tblock group %llu mode %o links %u uid %u gid %u rdev %llu\n"
	       "\t\tsequence %llu flags 0x%llx(%s)\n",
	       (unsigned long long)btrfs_inode_generation(eb, ii),
	       (unsigned long long)btrfs_inode_transid(eb, ii),
	       (unsigned long long)btrfs_inode_size(eb, ii),
	       (unsigned long long)btrfs_inode_nbytes(eb, ii),
	       (unsigned long long)btrfs_inode_block_group(eb,ii),
	       btrfs_inode_mode(eb, ii),
	       btrfs_inode_nlink(eb, ii),
	       btrfs_inode_uid(eb, ii),
	       btrfs_inode_gid(eb, ii),
	       (unsigned long long)btrfs_inode_rdev(eb,ii),
	       (unsigned long long)btrfs_inode_flags(eb,ii),
	       (unsigned long long)btrfs_inode_sequence(eb, ii),
	       flags_str);
	print_timespec(eb, btrfs_inode_atime(ii), "\t\tatime ", "\n");
	print_timespec(eb, btrfs_inode_ctime(ii), "\t\tctime ", "\n");
	print_timespec(eb, btrfs_inode_mtime(ii), "\t\tmtime ", "\n");
	print_timespec(eb, btrfs_inode_otime(ii), "\t\totime ", "\n");
}
Example #2
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);
	}
}
Example #3
0
/*
 * Unlink an inode, which will remove its backref and corresponding dir_index/
 * dir_item if any of them exists.
 *
 * If an inode's nlink is reduced to 0 and 'add_orphan' is true, it will be
 * added to orphan inode and waiting to be deleted by next kernel mount.
 */
int btrfs_unlink(struct btrfs_trans_handle *trans, struct btrfs_root *root,
		 u64 ino, u64 parent_ino, u64 index, const char *name,
		 int namelen, int add_orphan)
{
	struct btrfs_path *path;
	struct btrfs_key key;
	struct btrfs_inode_item *inode_item;
	struct btrfs_inode_ref *inode_ref;
	struct btrfs_dir_item *dir_item;
	u64 inode_size;
	u32 nlinks;
	int del_inode_ref = 0;
	int del_dir_item = 0;
	int del_dir_index = 0;
	int ret = 0;

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

	/* check the ref and backref exists */
	inode_ref = btrfs_lookup_inode_ref(trans, root, path, name, namelen,
					   ino, parent_ino, index, 0);
	if (IS_ERR(inode_ref)) {
		ret = PTR_ERR(inode_ref);
		goto out;
	}
	if (inode_ref)
		del_inode_ref = 1;
	btrfs_release_path(path);

	dir_item = btrfs_lookup_dir_item(NULL, root, path, parent_ino,
					 name, namelen, 0);
	if (IS_ERR(dir_item)) {
		ret = PTR_ERR(dir_item);
		goto out;
	}
	if (dir_item)
		del_dir_item = 1;
	btrfs_release_path(path);

	dir_item = btrfs_lookup_dir_index(NULL, root, path, parent_ino,
					  name, namelen, index, 0);
	/*
	 * Since lookup_dir_index() will return -ENOENT when not found,
	 * we need to do extra check.
	 */
	if (IS_ERR(dir_item) && PTR_ERR(dir_item) == -ENOENT)
		dir_item = NULL;
	if (IS_ERR(dir_item)) {
		ret = PTR_ERR(dir_item);
		goto out;
	}
	if (dir_item)
		del_dir_index = 1;
	btrfs_release_path(path);

	if (!del_inode_ref && !del_dir_item && !del_dir_index) {
		/* All not found, shouldn't happen */
		ret = -ENOENT;
		goto out;
	}

	if (del_inode_ref) {
		/* Only decrease nlink when deleting inode_ref */
		key.objectid = ino;
		key.type = BTRFS_INODE_ITEM_KEY;
		key.offset = 0;
		ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
		if (ret) {
			if (ret > 0)
				ret = -ENOENT;
			goto out;
		}
		inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0],
					    struct btrfs_inode_item);
		nlinks = btrfs_inode_nlink(path->nodes[0], inode_item);
		if (nlinks > 0)
			nlinks--;
		btrfs_set_inode_nlink(path->nodes[0], inode_item, nlinks);
		btrfs_mark_buffer_dirty(path->nodes[0]);
		btrfs_release_path(path);

		/* For nlinks == 0, add it to orphan list if needed */
		if (nlinks == 0 && add_orphan) {
			ret = btrfs_add_orphan_item(trans, root, path, ino);
			if (ret < 0)
				goto out;
			btrfs_mark_buffer_dirty(path->nodes[0]);
			btrfs_release_path(path);
		}

		ret = btrfs_del_inode_ref(trans, root, name, namelen, ino,
					  parent_ino, &index);
		if (ret < 0)
			goto out;
	}

	if (del_dir_index) {
		dir_item = btrfs_lookup_dir_index(trans, root, path,
						  parent_ino, name, namelen,
						  index, -1);
		if (IS_ERR(dir_item)) {
			ret = PTR_ERR(dir_item);
			goto out;
		}
		if (!dir_item) {
			ret = -ENOENT;
			goto out;
		}
		ret = btrfs_delete_one_dir_name(trans, root, path, dir_item);
		if (ret)
			goto out;
		btrfs_release_path(path);

		/* Update inode size of the parent inode */
		key.objectid = parent_ino;
		key.type = BTRFS_INODE_ITEM_KEY;
		key.offset = 0;
		ret = btrfs_search_slot(trans, root, &key, path, 1, 1);
		if (ret)
			goto out;
		inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0],
					    struct btrfs_inode_item);
		inode_size = btrfs_inode_size(path->nodes[0], inode_item);
		if (inode_size >= namelen)
			inode_size -= namelen;
		btrfs_set_inode_size(path->nodes[0], inode_item, inode_size);
		btrfs_mark_buffer_dirty(path->nodes[0]);
		btrfs_release_path(path);
	}

	if (del_dir_item) {
		dir_item = btrfs_lookup_dir_item(trans, root, path, parent_ino,
						 name, namelen, -1);
		if (IS_ERR(dir_item)) {
			ret = PTR_ERR(dir_item);
			goto out;
		}
		if (!dir_item) {
			ret = -ENOENT;
			goto out;
		}
		ret = btrfs_delete_one_dir_name(trans, root, path, dir_item);
		if (ret < 0)
			goto out;
		btrfs_release_path(path);

		/* Update inode size of the parent inode */
		key.objectid = parent_ino;
		key.type = BTRFS_INODE_ITEM_KEY;
		key.offset = 0;
		ret = btrfs_search_slot(trans, root, &key, path, 1, 1);
		if (ret)
			goto out;
		inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0],
					    struct btrfs_inode_item);
		inode_size = btrfs_inode_size(path->nodes[0], inode_item);
		if (inode_size >= namelen)
			inode_size -= namelen;
		btrfs_set_inode_size(path->nodes[0], inode_item, inode_size);
		btrfs_mark_buffer_dirty(path->nodes[0]);
		btrfs_release_path(path);
	}

out:
	btrfs_free_path(path);
	return ret;
}
Example #4
0
/*
 * Add dir_item/index for 'parent_ino' if add_backref is true, also insert a
 * backref from the ino to parent dir and update the nlink(Kernel version does
 * not do this thing)
 *
 * Currently only supports adding link from an inode to another inode.
 */
int btrfs_add_link(struct btrfs_trans_handle *trans, struct btrfs_root *root,
		   u64 ino, u64 parent_ino, char *name, int namelen,
		   u8 type, u64 *index, int add_backref)
{
	struct btrfs_path *path;
	struct btrfs_key key;
	struct btrfs_inode_item *inode_item;
	u32 nlink;
	u64 inode_size;
	u64 ret_index = 0;
	int ret = 0;

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

	if (index && *index) {
		ret_index = *index;
	} else {
		ret = btrfs_find_free_dir_index(root, parent_ino, &ret_index);
		if (ret < 0)
			goto out;
	}

	ret = check_dir_conflict(root, name, namelen, parent_ino, ret_index);
	if (ret < 0)
		goto out;

	/* Add inode ref */
	if (add_backref) {
		ret = btrfs_insert_inode_ref(trans, root, name, namelen,
					     ino, parent_ino, ret_index);
		if (ret < 0)
			goto out;

		/* Update nlinks for the inode */
		key.objectid = ino;
		key.type = BTRFS_INODE_ITEM_KEY;
		key.offset = 0;
		ret = btrfs_search_slot(trans, root, &key, path, 1, 1);
		if (ret) {
			if (ret > 0)
				ret = -ENOENT;
			goto out;
		}
		inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0],
				    struct btrfs_inode_item);
		nlink = btrfs_inode_nlink(path->nodes[0], inode_item);
		nlink++;
		btrfs_set_inode_nlink(path->nodes[0], inode_item, nlink);
		btrfs_mark_buffer_dirty(path->nodes[0]);
		btrfs_release_path(path);
	}

	/* Add dir_item and dir_index */
	key.objectid = ino;
	key.type = BTRFS_INODE_ITEM_KEY;
	key.offset = 0;
	ret = btrfs_insert_dir_item(trans, root, name, namelen, parent_ino,
				    &key, type, ret_index);
	if (ret < 0)
		goto out;

	/* Update inode size of the parent inode */
	key.objectid = parent_ino;
	key.type = BTRFS_INODE_ITEM_KEY;
	key.offset = 0;
	ret = btrfs_search_slot(trans, root, &key, path, 1, 1);
	if (ret)
		goto out;
	inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0],
				    struct btrfs_inode_item);
	inode_size = btrfs_inode_size(path->nodes[0], inode_item);
	inode_size += namelen * 2;
	btrfs_set_inode_size(path->nodes[0], inode_item, inode_size);
	btrfs_mark_buffer_dirty(path->nodes[0]);
	btrfs_release_path(path);

out:
	btrfs_free_path(path);
	if (ret == 0 && index)
		*index = ret_index;
	return ret;
}
Example #5
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);
	}
}