#include "print-tree.h"
#include "utils.h"
#include "ulist.h"
+#include "rbtree-utils.h"
#include "qgroup-verify.h"
static void add_bytes(u64 root_objectid, u64 num_bytes, int exclusive);
+struct qgroup_info {
+ u64 referenced;
+ u64 referenced_compressed;
+ u64 exclusive;
+ u64 exclusive_compressed;
+};
+
struct qgroup_count {
- u64 qgroupid;
+ u64 qgroupid;
+ int subvol_exists;
- struct btrfs_disk_key key;
- struct btrfs_qgroup_info_item diskinfo;
+ struct btrfs_disk_key key;
+ struct qgroup_info diskinfo;
- struct btrfs_qgroup_info_item info;
+ struct qgroup_info info;
- struct rb_node rb_node;
+ struct rb_node rb_node;
};
-struct counts_tree {
+static struct counts_tree {
struct rb_root root;
unsigned int num_groups;
} counts = { .root = RB_ROOT };
-struct rb_root by_bytenr = RB_ROOT;
+static struct rb_root by_bytenr = RB_ROOT;
/*
* List of interior tree blocks. We walk this list after loading the
* finding roots to account against.
*
* An implied ref is when a tree block has refs on it that may not
- * exist in any of it's child nodes. Even though the refs might not
+ * exist in any of its child nodes. Even though the refs might not
* exist further down the tree, the fact that our interior node has a
- * ref means we need to account anything below it to all it's roots.
+ * ref means we need to account anything below it to all its roots.
*/
-struct ulist *tree_blocks = NULL; /* unode->val = bytenr, ->aux
- * = tree_block pointer */
+static struct ulist *tree_blocks = NULL; /* unode->val = bytenr, ->aux
+ * = tree_block pointer */
struct tree_block {
int level;
u64 num_bytes;
} while (node && ref->bytenr == parent);
}
+static void print_subvol_info(u64 subvolid, u64 bytenr, u64 num_bytes,
+ struct ulist *roots);
/*
* Account each ref. Walk the refs, for each set of refs in a
* given bytenr:
* - Walk ref_roots ulist, adding extent bytes to each qgroup count that
* cooresponds to a found root.
*/
-static void account_all_refs(void)
+static void account_all_refs(int do_qgroups, u64 search_subvol)
{
int exclusive;
struct ref *ref;
else
exclusive = 0;
+ if (search_subvol)
+ print_subvol_info(search_subvol, bytenr, num_bytes,
+ roots);
+
ULIST_ITER_INIT(&uiter);
while ((unode = ulist_next(roots, &uiter))) {
BUG_ON(unode->val == 0ULL);
/* We only want to account fs trees */
- if (is_fstree(unode->val))
+ if (is_fstree(unode->val) && do_qgroups)
add_bytes(unode->val, num_bytes, exclusive);
}
}
static inline struct tree_block *unode_tree_block(struct ulist_node *unode)
{
- return (struct tree_block *)unode->aux;
+ return u64_to_ptr(unode->aux);
}
static inline u64 unode_bytenr(struct ulist_node *unode)
{
if (block) {
block->num_bytes = num_bytes;
block->level = level;
- if (ulist_add(tree_blocks, bytenr, (unsigned long long)block, 0) >= 0)
+ if (ulist_add(tree_blocks, bytenr, ptr_to_u64(block), 0) >= 0)
return 0;
free(block);
}
// bytenr, num_bytes, ref_parent);
eb = read_tree_block(root, bytenr, num_bytes, 0);
- if (!eb)
+ if (!extent_buffer_uptodate(eb))
return -EIO;
ret = 0;
struct tree_block *block)
{
int ret;
- u64 root_bytenr = resolve_one_root(bytenr);
+ u64 root_id = resolve_one_root(bytenr);
struct btrfs_root *root;
struct btrfs_key key;
- key.objectid = root_bytenr;
+ key.objectid = root_id;
key.type = BTRFS_ROOT_ITEM_KEY;
key.offset = (u64)-1;
struct btrfs_qgroup_info_item *disk)
{
struct qgroup_count *c = calloc(1, sizeof(*c));
- struct btrfs_qgroup_info_item *item;
+ struct qgroup_info *item;
if (c) {
c->qgroupid = btrfs_disk_key_offset(key);
c->key = *key;
item = &c->diskinfo;
- item->generation = btrfs_qgroup_info_generation(leaf, disk);
item->referenced = btrfs_qgroup_info_referenced(leaf, disk);
item->referenced_compressed =
btrfs_qgroup_info_referenced_compressed(leaf, disk);
static void add_bytes(u64 root_objectid, u64 num_bytes, int exclusive)
{
struct qgroup_count *count = find_count(root_objectid);
- struct btrfs_qgroup_info_item *qg;
+ struct qgroup_info *qg;
BUG_ON(num_bytes < 4096); /* Random sanity check. */
{
int ret;
struct btrfs_root *root = info->quota_root;
+ struct btrfs_root *tmproot;
struct btrfs_path path;
struct btrfs_key key;
+ struct btrfs_key root_key;
struct btrfs_disk_key disk_key;
struct extent_buffer *leaf;
struct btrfs_qgroup_info_item *item;
fprintf(stderr, "ERROR: out of memory\n");
goto out;
}
+
+ root_key.objectid = key.offset;
+ root_key.type = BTRFS_ROOT_ITEM_KEY;
+ root_key.offset = (u64)-1;
+ tmproot = btrfs_read_fs_root_no_cache(info, &root_key);
+ if (tmproot && !IS_ERR(tmproot)) {
+ count->subvol_exists = 1;
+ free(tmproot);
+ }
}
ret = btrfs_next_leaf(root, &path);
static void print_qgroup_difference(struct qgroup_count *count, int verbose)
{
int is_different;
- struct btrfs_qgroup_info_item *info = &count->info;
- struct btrfs_qgroup_info_item *disk = &count->diskinfo;
+ struct qgroup_info *info = &count->info;
+ struct qgroup_info *disk = &count->diskinfo;
long long excl_diff = info->exclusive - disk->exclusive;
long long ref_diff = info->referenced - disk->referenced;
is_different = excl_diff || ref_diff;
- if (verbose || is_different) {
+ if (verbose || (is_different && count->subvol_exists)) {
printf("Counts for qgroup id: %llu %s\n",
(unsigned long long)count->qgroupid,
is_different ? "are different" : "");
goto out;
}
- account_all_refs();
+ account_all_refs(1, 0);
out:
/*
free_ref_tree(&by_bytenr);
return ret;
}
+
+static void __print_subvol_info(u64 bytenr, u64 num_bytes, struct ulist *roots)
+{
+ int n = roots->nnodes;
+ struct ulist_iterator uiter;
+ struct ulist_node *unode;
+
+ printf("%llu\t%llu\t%d\t", bytenr, num_bytes, n);
+
+ ULIST_ITER_INIT(&uiter);
+ while ((unode = ulist_next(roots, &uiter))) {
+ printf("%llu ", unode->val);
+ }
+ printf("\n");
+}
+
+static void print_subvol_info(u64 subvolid, u64 bytenr, u64 num_bytes,
+ struct ulist *roots)
+{
+ struct ulist_iterator uiter;
+ struct ulist_node *unode;
+
+ ULIST_ITER_INIT(&uiter);
+ while ((unode = ulist_next(roots, &uiter))) {
+ BUG_ON(unode->val == 0ULL);
+ if (unode->val == subvolid) {
+ __print_subvol_info(bytenr, num_bytes, roots);
+ return;
+ }
+ }
+
+
+}
+
+int print_extent_state(struct btrfs_fs_info *info, u64 subvol)
+{
+ int ret;
+
+ tree_blocks = ulist_alloc(0);
+ if (!tree_blocks) {
+ fprintf(stderr,
+ "ERROR: Out of memory while allocating ulist.\n");
+ return ENOMEM;
+ }
+
+ /*
+ * Put all extent refs into our rbtree
+ */
+ ret = scan_extents(info, 0, ~0ULL);
+ if (ret) {
+ fprintf(stderr, "ERROR: while scanning extent tree: %d\n", ret);
+ goto out;
+ }
+
+ ret = map_implied_refs(info);
+ if (ret) {
+ fprintf(stderr, "ERROR: while mapping refs: %d\n", ret);
+ goto out;
+ }
+
+ printf("Offset\t\tLen\tRoot Refs\tRoots\n");
+ account_all_refs(0, subvol);
+
+out:
+ free_tree_blocks();
+ free_ref_tree(&by_bytenr);
+ return ret;
+}
+