18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2014 Facebook.  All rights reserved.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/sched.h>
78c2ecf20Sopenharmony_ci#include <linux/stacktrace.h>
88c2ecf20Sopenharmony_ci#include "ctree.h"
98c2ecf20Sopenharmony_ci#include "disk-io.h"
108c2ecf20Sopenharmony_ci#include "locking.h"
118c2ecf20Sopenharmony_ci#include "delayed-ref.h"
128c2ecf20Sopenharmony_ci#include "ref-verify.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci/*
158c2ecf20Sopenharmony_ci * Used to keep track the roots and number of refs each root has for a given
168c2ecf20Sopenharmony_ci * bytenr.  This just tracks the number of direct references, no shared
178c2ecf20Sopenharmony_ci * references.
188c2ecf20Sopenharmony_ci */
198c2ecf20Sopenharmony_cistruct root_entry {
208c2ecf20Sopenharmony_ci	u64 root_objectid;
218c2ecf20Sopenharmony_ci	u64 num_refs;
228c2ecf20Sopenharmony_ci	struct rb_node node;
238c2ecf20Sopenharmony_ci};
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/*
268c2ecf20Sopenharmony_ci * These are meant to represent what should exist in the extent tree, these can
278c2ecf20Sopenharmony_ci * be used to verify the extent tree is consistent as these should all match
288c2ecf20Sopenharmony_ci * what the extent tree says.
298c2ecf20Sopenharmony_ci */
308c2ecf20Sopenharmony_cistruct ref_entry {
318c2ecf20Sopenharmony_ci	u64 root_objectid;
328c2ecf20Sopenharmony_ci	u64 parent;
338c2ecf20Sopenharmony_ci	u64 owner;
348c2ecf20Sopenharmony_ci	u64 offset;
358c2ecf20Sopenharmony_ci	u64 num_refs;
368c2ecf20Sopenharmony_ci	struct rb_node node;
378c2ecf20Sopenharmony_ci};
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define MAX_TRACE	16
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/*
428c2ecf20Sopenharmony_ci * Whenever we add/remove a reference we record the action.  The action maps
438c2ecf20Sopenharmony_ci * back to the delayed ref action.  We hold the ref we are changing in the
448c2ecf20Sopenharmony_ci * action so we can account for the history properly, and we record the root we
458c2ecf20Sopenharmony_ci * were called with since it could be different from ref_root.  We also store
468c2ecf20Sopenharmony_ci * stack traces because that's how I roll.
478c2ecf20Sopenharmony_ci */
488c2ecf20Sopenharmony_cistruct ref_action {
498c2ecf20Sopenharmony_ci	int action;
508c2ecf20Sopenharmony_ci	u64 root;
518c2ecf20Sopenharmony_ci	struct ref_entry ref;
528c2ecf20Sopenharmony_ci	struct list_head list;
538c2ecf20Sopenharmony_ci	unsigned long trace[MAX_TRACE];
548c2ecf20Sopenharmony_ci	unsigned int trace_len;
558c2ecf20Sopenharmony_ci};
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci/*
588c2ecf20Sopenharmony_ci * One of these for every block we reference, it holds the roots and references
598c2ecf20Sopenharmony_ci * to it as well as all of the ref actions that have occurred to it.  We never
608c2ecf20Sopenharmony_ci * free it until we unmount the file system in order to make sure re-allocations
618c2ecf20Sopenharmony_ci * are happening properly.
628c2ecf20Sopenharmony_ci */
638c2ecf20Sopenharmony_cistruct block_entry {
648c2ecf20Sopenharmony_ci	u64 bytenr;
658c2ecf20Sopenharmony_ci	u64 len;
668c2ecf20Sopenharmony_ci	u64 num_refs;
678c2ecf20Sopenharmony_ci	int metadata;
688c2ecf20Sopenharmony_ci	int from_disk;
698c2ecf20Sopenharmony_ci	struct rb_root roots;
708c2ecf20Sopenharmony_ci	struct rb_root refs;
718c2ecf20Sopenharmony_ci	struct rb_node node;
728c2ecf20Sopenharmony_ci	struct list_head actions;
738c2ecf20Sopenharmony_ci};
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic struct block_entry *insert_block_entry(struct rb_root *root,
768c2ecf20Sopenharmony_ci					      struct block_entry *be)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	struct rb_node **p = &root->rb_node;
798c2ecf20Sopenharmony_ci	struct rb_node *parent_node = NULL;
808c2ecf20Sopenharmony_ci	struct block_entry *entry;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	while (*p) {
838c2ecf20Sopenharmony_ci		parent_node = *p;
848c2ecf20Sopenharmony_ci		entry = rb_entry(parent_node, struct block_entry, node);
858c2ecf20Sopenharmony_ci		if (entry->bytenr > be->bytenr)
868c2ecf20Sopenharmony_ci			p = &(*p)->rb_left;
878c2ecf20Sopenharmony_ci		else if (entry->bytenr < be->bytenr)
888c2ecf20Sopenharmony_ci			p = &(*p)->rb_right;
898c2ecf20Sopenharmony_ci		else
908c2ecf20Sopenharmony_ci			return entry;
918c2ecf20Sopenharmony_ci	}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	rb_link_node(&be->node, parent_node, p);
948c2ecf20Sopenharmony_ci	rb_insert_color(&be->node, root);
958c2ecf20Sopenharmony_ci	return NULL;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic struct block_entry *lookup_block_entry(struct rb_root *root, u64 bytenr)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	struct rb_node *n;
1018c2ecf20Sopenharmony_ci	struct block_entry *entry = NULL;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	n = root->rb_node;
1048c2ecf20Sopenharmony_ci	while (n) {
1058c2ecf20Sopenharmony_ci		entry = rb_entry(n, struct block_entry, node);
1068c2ecf20Sopenharmony_ci		if (entry->bytenr < bytenr)
1078c2ecf20Sopenharmony_ci			n = n->rb_right;
1088c2ecf20Sopenharmony_ci		else if (entry->bytenr > bytenr)
1098c2ecf20Sopenharmony_ci			n = n->rb_left;
1108c2ecf20Sopenharmony_ci		else
1118c2ecf20Sopenharmony_ci			return entry;
1128c2ecf20Sopenharmony_ci	}
1138c2ecf20Sopenharmony_ci	return NULL;
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic struct root_entry *insert_root_entry(struct rb_root *root,
1178c2ecf20Sopenharmony_ci					    struct root_entry *re)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	struct rb_node **p = &root->rb_node;
1208c2ecf20Sopenharmony_ci	struct rb_node *parent_node = NULL;
1218c2ecf20Sopenharmony_ci	struct root_entry *entry;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	while (*p) {
1248c2ecf20Sopenharmony_ci		parent_node = *p;
1258c2ecf20Sopenharmony_ci		entry = rb_entry(parent_node, struct root_entry, node);
1268c2ecf20Sopenharmony_ci		if (entry->root_objectid > re->root_objectid)
1278c2ecf20Sopenharmony_ci			p = &(*p)->rb_left;
1288c2ecf20Sopenharmony_ci		else if (entry->root_objectid < re->root_objectid)
1298c2ecf20Sopenharmony_ci			p = &(*p)->rb_right;
1308c2ecf20Sopenharmony_ci		else
1318c2ecf20Sopenharmony_ci			return entry;
1328c2ecf20Sopenharmony_ci	}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	rb_link_node(&re->node, parent_node, p);
1358c2ecf20Sopenharmony_ci	rb_insert_color(&re->node, root);
1368c2ecf20Sopenharmony_ci	return NULL;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic int comp_refs(struct ref_entry *ref1, struct ref_entry *ref2)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	if (ref1->root_objectid < ref2->root_objectid)
1438c2ecf20Sopenharmony_ci		return -1;
1448c2ecf20Sopenharmony_ci	if (ref1->root_objectid > ref2->root_objectid)
1458c2ecf20Sopenharmony_ci		return 1;
1468c2ecf20Sopenharmony_ci	if (ref1->parent < ref2->parent)
1478c2ecf20Sopenharmony_ci		return -1;
1488c2ecf20Sopenharmony_ci	if (ref1->parent > ref2->parent)
1498c2ecf20Sopenharmony_ci		return 1;
1508c2ecf20Sopenharmony_ci	if (ref1->owner < ref2->owner)
1518c2ecf20Sopenharmony_ci		return -1;
1528c2ecf20Sopenharmony_ci	if (ref1->owner > ref2->owner)
1538c2ecf20Sopenharmony_ci		return 1;
1548c2ecf20Sopenharmony_ci	if (ref1->offset < ref2->offset)
1558c2ecf20Sopenharmony_ci		return -1;
1568c2ecf20Sopenharmony_ci	if (ref1->offset > ref2->offset)
1578c2ecf20Sopenharmony_ci		return 1;
1588c2ecf20Sopenharmony_ci	return 0;
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic struct ref_entry *insert_ref_entry(struct rb_root *root,
1628c2ecf20Sopenharmony_ci					  struct ref_entry *ref)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	struct rb_node **p = &root->rb_node;
1658c2ecf20Sopenharmony_ci	struct rb_node *parent_node = NULL;
1668c2ecf20Sopenharmony_ci	struct ref_entry *entry;
1678c2ecf20Sopenharmony_ci	int cmp;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	while (*p) {
1708c2ecf20Sopenharmony_ci		parent_node = *p;
1718c2ecf20Sopenharmony_ci		entry = rb_entry(parent_node, struct ref_entry, node);
1728c2ecf20Sopenharmony_ci		cmp = comp_refs(entry, ref);
1738c2ecf20Sopenharmony_ci		if (cmp > 0)
1748c2ecf20Sopenharmony_ci			p = &(*p)->rb_left;
1758c2ecf20Sopenharmony_ci		else if (cmp < 0)
1768c2ecf20Sopenharmony_ci			p = &(*p)->rb_right;
1778c2ecf20Sopenharmony_ci		else
1788c2ecf20Sopenharmony_ci			return entry;
1798c2ecf20Sopenharmony_ci	}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	rb_link_node(&ref->node, parent_node, p);
1828c2ecf20Sopenharmony_ci	rb_insert_color(&ref->node, root);
1838c2ecf20Sopenharmony_ci	return NULL;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic struct root_entry *lookup_root_entry(struct rb_root *root, u64 objectid)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	struct rb_node *n;
1908c2ecf20Sopenharmony_ci	struct root_entry *entry = NULL;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	n = root->rb_node;
1938c2ecf20Sopenharmony_ci	while (n) {
1948c2ecf20Sopenharmony_ci		entry = rb_entry(n, struct root_entry, node);
1958c2ecf20Sopenharmony_ci		if (entry->root_objectid < objectid)
1968c2ecf20Sopenharmony_ci			n = n->rb_right;
1978c2ecf20Sopenharmony_ci		else if (entry->root_objectid > objectid)
1988c2ecf20Sopenharmony_ci			n = n->rb_left;
1998c2ecf20Sopenharmony_ci		else
2008c2ecf20Sopenharmony_ci			return entry;
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci	return NULL;
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci#ifdef CONFIG_STACKTRACE
2068c2ecf20Sopenharmony_cistatic void __save_stack_trace(struct ref_action *ra)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	ra->trace_len = stack_trace_save(ra->trace, MAX_TRACE, 2);
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cistatic void __print_stack_trace(struct btrfs_fs_info *fs_info,
2128c2ecf20Sopenharmony_ci				struct ref_action *ra)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	if (ra->trace_len == 0) {
2158c2ecf20Sopenharmony_ci		btrfs_err(fs_info, "  ref-verify: no stacktrace");
2168c2ecf20Sopenharmony_ci		return;
2178c2ecf20Sopenharmony_ci	}
2188c2ecf20Sopenharmony_ci	stack_trace_print(ra->trace, ra->trace_len, 2);
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci#else
2218c2ecf20Sopenharmony_cistatic void inline __save_stack_trace(struct ref_action *ra)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_cistatic void inline __print_stack_trace(struct btrfs_fs_info *fs_info,
2268c2ecf20Sopenharmony_ci				       struct ref_action *ra)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	btrfs_err(fs_info, "  ref-verify: no stacktrace support");
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci#endif
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic void free_block_entry(struct block_entry *be)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	struct root_entry *re;
2358c2ecf20Sopenharmony_ci	struct ref_entry *ref;
2368c2ecf20Sopenharmony_ci	struct ref_action *ra;
2378c2ecf20Sopenharmony_ci	struct rb_node *n;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	while ((n = rb_first(&be->roots))) {
2408c2ecf20Sopenharmony_ci		re = rb_entry(n, struct root_entry, node);
2418c2ecf20Sopenharmony_ci		rb_erase(&re->node, &be->roots);
2428c2ecf20Sopenharmony_ci		kfree(re);
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	while((n = rb_first(&be->refs))) {
2468c2ecf20Sopenharmony_ci		ref = rb_entry(n, struct ref_entry, node);
2478c2ecf20Sopenharmony_ci		rb_erase(&ref->node, &be->refs);
2488c2ecf20Sopenharmony_ci		kfree(ref);
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	while (!list_empty(&be->actions)) {
2528c2ecf20Sopenharmony_ci		ra = list_first_entry(&be->actions, struct ref_action,
2538c2ecf20Sopenharmony_ci				      list);
2548c2ecf20Sopenharmony_ci		list_del(&ra->list);
2558c2ecf20Sopenharmony_ci		kfree(ra);
2568c2ecf20Sopenharmony_ci	}
2578c2ecf20Sopenharmony_ci	kfree(be);
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistatic struct block_entry *add_block_entry(struct btrfs_fs_info *fs_info,
2618c2ecf20Sopenharmony_ci					   u64 bytenr, u64 len,
2628c2ecf20Sopenharmony_ci					   u64 root_objectid)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	struct block_entry *be = NULL, *exist;
2658c2ecf20Sopenharmony_ci	struct root_entry *re = NULL;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	re = kzalloc(sizeof(struct root_entry), GFP_KERNEL);
2688c2ecf20Sopenharmony_ci	be = kzalloc(sizeof(struct block_entry), GFP_KERNEL);
2698c2ecf20Sopenharmony_ci	if (!be || !re) {
2708c2ecf20Sopenharmony_ci		kfree(re);
2718c2ecf20Sopenharmony_ci		kfree(be);
2728c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci	be->bytenr = bytenr;
2758c2ecf20Sopenharmony_ci	be->len = len;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	re->root_objectid = root_objectid;
2788c2ecf20Sopenharmony_ci	re->num_refs = 0;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	spin_lock(&fs_info->ref_verify_lock);
2818c2ecf20Sopenharmony_ci	exist = insert_block_entry(&fs_info->block_tree, be);
2828c2ecf20Sopenharmony_ci	if (exist) {
2838c2ecf20Sopenharmony_ci		if (root_objectid) {
2848c2ecf20Sopenharmony_ci			struct root_entry *exist_re;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci			exist_re = insert_root_entry(&exist->roots, re);
2878c2ecf20Sopenharmony_ci			if (exist_re)
2888c2ecf20Sopenharmony_ci				kfree(re);
2898c2ecf20Sopenharmony_ci		} else {
2908c2ecf20Sopenharmony_ci			kfree(re);
2918c2ecf20Sopenharmony_ci		}
2928c2ecf20Sopenharmony_ci		kfree(be);
2938c2ecf20Sopenharmony_ci		return exist;
2948c2ecf20Sopenharmony_ci	}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	be->num_refs = 0;
2978c2ecf20Sopenharmony_ci	be->metadata = 0;
2988c2ecf20Sopenharmony_ci	be->from_disk = 0;
2998c2ecf20Sopenharmony_ci	be->roots = RB_ROOT;
3008c2ecf20Sopenharmony_ci	be->refs = RB_ROOT;
3018c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&be->actions);
3028c2ecf20Sopenharmony_ci	if (root_objectid)
3038c2ecf20Sopenharmony_ci		insert_root_entry(&be->roots, re);
3048c2ecf20Sopenharmony_ci	else
3058c2ecf20Sopenharmony_ci		kfree(re);
3068c2ecf20Sopenharmony_ci	return be;
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistatic int add_tree_block(struct btrfs_fs_info *fs_info, u64 ref_root,
3108c2ecf20Sopenharmony_ci			  u64 parent, u64 bytenr, int level)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	struct block_entry *be;
3138c2ecf20Sopenharmony_ci	struct root_entry *re;
3148c2ecf20Sopenharmony_ci	struct ref_entry *ref = NULL, *exist;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	ref = kmalloc(sizeof(struct ref_entry), GFP_KERNEL);
3178c2ecf20Sopenharmony_ci	if (!ref)
3188c2ecf20Sopenharmony_ci		return -ENOMEM;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	if (parent)
3218c2ecf20Sopenharmony_ci		ref->root_objectid = 0;
3228c2ecf20Sopenharmony_ci	else
3238c2ecf20Sopenharmony_ci		ref->root_objectid = ref_root;
3248c2ecf20Sopenharmony_ci	ref->parent = parent;
3258c2ecf20Sopenharmony_ci	ref->owner = level;
3268c2ecf20Sopenharmony_ci	ref->offset = 0;
3278c2ecf20Sopenharmony_ci	ref->num_refs = 1;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	be = add_block_entry(fs_info, bytenr, fs_info->nodesize, ref_root);
3308c2ecf20Sopenharmony_ci	if (IS_ERR(be)) {
3318c2ecf20Sopenharmony_ci		kfree(ref);
3328c2ecf20Sopenharmony_ci		return PTR_ERR(be);
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci	be->num_refs++;
3358c2ecf20Sopenharmony_ci	be->from_disk = 1;
3368c2ecf20Sopenharmony_ci	be->metadata = 1;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	if (!parent) {
3398c2ecf20Sopenharmony_ci		ASSERT(ref_root);
3408c2ecf20Sopenharmony_ci		re = lookup_root_entry(&be->roots, ref_root);
3418c2ecf20Sopenharmony_ci		ASSERT(re);
3428c2ecf20Sopenharmony_ci		re->num_refs++;
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci	exist = insert_ref_entry(&be->refs, ref);
3458c2ecf20Sopenharmony_ci	if (exist) {
3468c2ecf20Sopenharmony_ci		exist->num_refs++;
3478c2ecf20Sopenharmony_ci		kfree(ref);
3488c2ecf20Sopenharmony_ci	}
3498c2ecf20Sopenharmony_ci	spin_unlock(&fs_info->ref_verify_lock);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	return 0;
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_cistatic int add_shared_data_ref(struct btrfs_fs_info *fs_info,
3558c2ecf20Sopenharmony_ci			       u64 parent, u32 num_refs, u64 bytenr,
3568c2ecf20Sopenharmony_ci			       u64 num_bytes)
3578c2ecf20Sopenharmony_ci{
3588c2ecf20Sopenharmony_ci	struct block_entry *be;
3598c2ecf20Sopenharmony_ci	struct ref_entry *ref;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	ref = kzalloc(sizeof(struct ref_entry), GFP_KERNEL);
3628c2ecf20Sopenharmony_ci	if (!ref)
3638c2ecf20Sopenharmony_ci		return -ENOMEM;
3648c2ecf20Sopenharmony_ci	be = add_block_entry(fs_info, bytenr, num_bytes, 0);
3658c2ecf20Sopenharmony_ci	if (IS_ERR(be)) {
3668c2ecf20Sopenharmony_ci		kfree(ref);
3678c2ecf20Sopenharmony_ci		return PTR_ERR(be);
3688c2ecf20Sopenharmony_ci	}
3698c2ecf20Sopenharmony_ci	be->num_refs += num_refs;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	ref->parent = parent;
3728c2ecf20Sopenharmony_ci	ref->num_refs = num_refs;
3738c2ecf20Sopenharmony_ci	if (insert_ref_entry(&be->refs, ref)) {
3748c2ecf20Sopenharmony_ci		spin_unlock(&fs_info->ref_verify_lock);
3758c2ecf20Sopenharmony_ci		btrfs_err(fs_info, "existing shared ref when reading from disk?");
3768c2ecf20Sopenharmony_ci		kfree(ref);
3778c2ecf20Sopenharmony_ci		return -EINVAL;
3788c2ecf20Sopenharmony_ci	}
3798c2ecf20Sopenharmony_ci	spin_unlock(&fs_info->ref_verify_lock);
3808c2ecf20Sopenharmony_ci	return 0;
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cistatic int add_extent_data_ref(struct btrfs_fs_info *fs_info,
3848c2ecf20Sopenharmony_ci			       struct extent_buffer *leaf,
3858c2ecf20Sopenharmony_ci			       struct btrfs_extent_data_ref *dref,
3868c2ecf20Sopenharmony_ci			       u64 bytenr, u64 num_bytes)
3878c2ecf20Sopenharmony_ci{
3888c2ecf20Sopenharmony_ci	struct block_entry *be;
3898c2ecf20Sopenharmony_ci	struct ref_entry *ref;
3908c2ecf20Sopenharmony_ci	struct root_entry *re;
3918c2ecf20Sopenharmony_ci	u64 ref_root = btrfs_extent_data_ref_root(leaf, dref);
3928c2ecf20Sopenharmony_ci	u64 owner = btrfs_extent_data_ref_objectid(leaf, dref);
3938c2ecf20Sopenharmony_ci	u64 offset = btrfs_extent_data_ref_offset(leaf, dref);
3948c2ecf20Sopenharmony_ci	u32 num_refs = btrfs_extent_data_ref_count(leaf, dref);
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	ref = kzalloc(sizeof(struct ref_entry), GFP_KERNEL);
3978c2ecf20Sopenharmony_ci	if (!ref)
3988c2ecf20Sopenharmony_ci		return -ENOMEM;
3998c2ecf20Sopenharmony_ci	be = add_block_entry(fs_info, bytenr, num_bytes, ref_root);
4008c2ecf20Sopenharmony_ci	if (IS_ERR(be)) {
4018c2ecf20Sopenharmony_ci		kfree(ref);
4028c2ecf20Sopenharmony_ci		return PTR_ERR(be);
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci	be->num_refs += num_refs;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	ref->parent = 0;
4078c2ecf20Sopenharmony_ci	ref->owner = owner;
4088c2ecf20Sopenharmony_ci	ref->root_objectid = ref_root;
4098c2ecf20Sopenharmony_ci	ref->offset = offset;
4108c2ecf20Sopenharmony_ci	ref->num_refs = num_refs;
4118c2ecf20Sopenharmony_ci	if (insert_ref_entry(&be->refs, ref)) {
4128c2ecf20Sopenharmony_ci		spin_unlock(&fs_info->ref_verify_lock);
4138c2ecf20Sopenharmony_ci		btrfs_err(fs_info, "existing ref when reading from disk?");
4148c2ecf20Sopenharmony_ci		kfree(ref);
4158c2ecf20Sopenharmony_ci		return -EINVAL;
4168c2ecf20Sopenharmony_ci	}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	re = lookup_root_entry(&be->roots, ref_root);
4198c2ecf20Sopenharmony_ci	if (!re) {
4208c2ecf20Sopenharmony_ci		spin_unlock(&fs_info->ref_verify_lock);
4218c2ecf20Sopenharmony_ci		btrfs_err(fs_info, "missing root in new block entry?");
4228c2ecf20Sopenharmony_ci		return -EINVAL;
4238c2ecf20Sopenharmony_ci	}
4248c2ecf20Sopenharmony_ci	re->num_refs += num_refs;
4258c2ecf20Sopenharmony_ci	spin_unlock(&fs_info->ref_verify_lock);
4268c2ecf20Sopenharmony_ci	return 0;
4278c2ecf20Sopenharmony_ci}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_cistatic int process_extent_item(struct btrfs_fs_info *fs_info,
4308c2ecf20Sopenharmony_ci			       struct btrfs_path *path, struct btrfs_key *key,
4318c2ecf20Sopenharmony_ci			       int slot, int *tree_block_level)
4328c2ecf20Sopenharmony_ci{
4338c2ecf20Sopenharmony_ci	struct btrfs_extent_item *ei;
4348c2ecf20Sopenharmony_ci	struct btrfs_extent_inline_ref *iref;
4358c2ecf20Sopenharmony_ci	struct btrfs_extent_data_ref *dref;
4368c2ecf20Sopenharmony_ci	struct btrfs_shared_data_ref *sref;
4378c2ecf20Sopenharmony_ci	struct extent_buffer *leaf = path->nodes[0];
4388c2ecf20Sopenharmony_ci	u32 item_size = btrfs_item_size_nr(leaf, slot);
4398c2ecf20Sopenharmony_ci	unsigned long end, ptr;
4408c2ecf20Sopenharmony_ci	u64 offset, flags, count;
4418c2ecf20Sopenharmony_ci	int type, ret;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item);
4448c2ecf20Sopenharmony_ci	flags = btrfs_extent_flags(leaf, ei);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	if ((key->type == BTRFS_EXTENT_ITEM_KEY) &&
4478c2ecf20Sopenharmony_ci	    flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
4488c2ecf20Sopenharmony_ci		struct btrfs_tree_block_info *info;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci		info = (struct btrfs_tree_block_info *)(ei + 1);
4518c2ecf20Sopenharmony_ci		*tree_block_level = btrfs_tree_block_level(leaf, info);
4528c2ecf20Sopenharmony_ci		iref = (struct btrfs_extent_inline_ref *)(info + 1);
4538c2ecf20Sopenharmony_ci	} else {
4548c2ecf20Sopenharmony_ci		if (key->type == BTRFS_METADATA_ITEM_KEY)
4558c2ecf20Sopenharmony_ci			*tree_block_level = key->offset;
4568c2ecf20Sopenharmony_ci		iref = (struct btrfs_extent_inline_ref *)(ei + 1);
4578c2ecf20Sopenharmony_ci	}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	ptr = (unsigned long)iref;
4608c2ecf20Sopenharmony_ci	end = (unsigned long)ei + item_size;
4618c2ecf20Sopenharmony_ci	while (ptr < end) {
4628c2ecf20Sopenharmony_ci		iref = (struct btrfs_extent_inline_ref *)ptr;
4638c2ecf20Sopenharmony_ci		type = btrfs_extent_inline_ref_type(leaf, iref);
4648c2ecf20Sopenharmony_ci		offset = btrfs_extent_inline_ref_offset(leaf, iref);
4658c2ecf20Sopenharmony_ci		switch (type) {
4668c2ecf20Sopenharmony_ci		case BTRFS_TREE_BLOCK_REF_KEY:
4678c2ecf20Sopenharmony_ci			ret = add_tree_block(fs_info, offset, 0, key->objectid,
4688c2ecf20Sopenharmony_ci					     *tree_block_level);
4698c2ecf20Sopenharmony_ci			break;
4708c2ecf20Sopenharmony_ci		case BTRFS_SHARED_BLOCK_REF_KEY:
4718c2ecf20Sopenharmony_ci			ret = add_tree_block(fs_info, 0, offset, key->objectid,
4728c2ecf20Sopenharmony_ci					     *tree_block_level);
4738c2ecf20Sopenharmony_ci			break;
4748c2ecf20Sopenharmony_ci		case BTRFS_EXTENT_DATA_REF_KEY:
4758c2ecf20Sopenharmony_ci			dref = (struct btrfs_extent_data_ref *)(&iref->offset);
4768c2ecf20Sopenharmony_ci			ret = add_extent_data_ref(fs_info, leaf, dref,
4778c2ecf20Sopenharmony_ci						  key->objectid, key->offset);
4788c2ecf20Sopenharmony_ci			break;
4798c2ecf20Sopenharmony_ci		case BTRFS_SHARED_DATA_REF_KEY:
4808c2ecf20Sopenharmony_ci			sref = (struct btrfs_shared_data_ref *)(iref + 1);
4818c2ecf20Sopenharmony_ci			count = btrfs_shared_data_ref_count(leaf, sref);
4828c2ecf20Sopenharmony_ci			ret = add_shared_data_ref(fs_info, offset, count,
4838c2ecf20Sopenharmony_ci						  key->objectid, key->offset);
4848c2ecf20Sopenharmony_ci			break;
4858c2ecf20Sopenharmony_ci		default:
4868c2ecf20Sopenharmony_ci			btrfs_err(fs_info, "invalid key type in iref");
4878c2ecf20Sopenharmony_ci			ret = -EINVAL;
4888c2ecf20Sopenharmony_ci			break;
4898c2ecf20Sopenharmony_ci		}
4908c2ecf20Sopenharmony_ci		if (ret)
4918c2ecf20Sopenharmony_ci			break;
4928c2ecf20Sopenharmony_ci		ptr += btrfs_extent_inline_ref_size(type);
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci	return ret;
4958c2ecf20Sopenharmony_ci}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_cistatic int process_leaf(struct btrfs_root *root,
4988c2ecf20Sopenharmony_ci			struct btrfs_path *path, u64 *bytenr, u64 *num_bytes)
4998c2ecf20Sopenharmony_ci{
5008c2ecf20Sopenharmony_ci	struct btrfs_fs_info *fs_info = root->fs_info;
5018c2ecf20Sopenharmony_ci	struct extent_buffer *leaf = path->nodes[0];
5028c2ecf20Sopenharmony_ci	struct btrfs_extent_data_ref *dref;
5038c2ecf20Sopenharmony_ci	struct btrfs_shared_data_ref *sref;
5048c2ecf20Sopenharmony_ci	u32 count;
5058c2ecf20Sopenharmony_ci	int i = 0, tree_block_level = 0, ret = 0;
5068c2ecf20Sopenharmony_ci	struct btrfs_key key;
5078c2ecf20Sopenharmony_ci	int nritems = btrfs_header_nritems(leaf);
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	for (i = 0; i < nritems; i++) {
5108c2ecf20Sopenharmony_ci		btrfs_item_key_to_cpu(leaf, &key, i);
5118c2ecf20Sopenharmony_ci		switch (key.type) {
5128c2ecf20Sopenharmony_ci		case BTRFS_EXTENT_ITEM_KEY:
5138c2ecf20Sopenharmony_ci			*num_bytes = key.offset;
5148c2ecf20Sopenharmony_ci			fallthrough;
5158c2ecf20Sopenharmony_ci		case BTRFS_METADATA_ITEM_KEY:
5168c2ecf20Sopenharmony_ci			*bytenr = key.objectid;
5178c2ecf20Sopenharmony_ci			ret = process_extent_item(fs_info, path, &key, i,
5188c2ecf20Sopenharmony_ci						  &tree_block_level);
5198c2ecf20Sopenharmony_ci			break;
5208c2ecf20Sopenharmony_ci		case BTRFS_TREE_BLOCK_REF_KEY:
5218c2ecf20Sopenharmony_ci			ret = add_tree_block(fs_info, key.offset, 0,
5228c2ecf20Sopenharmony_ci					     key.objectid, tree_block_level);
5238c2ecf20Sopenharmony_ci			break;
5248c2ecf20Sopenharmony_ci		case BTRFS_SHARED_BLOCK_REF_KEY:
5258c2ecf20Sopenharmony_ci			ret = add_tree_block(fs_info, 0, key.offset,
5268c2ecf20Sopenharmony_ci					     key.objectid, tree_block_level);
5278c2ecf20Sopenharmony_ci			break;
5288c2ecf20Sopenharmony_ci		case BTRFS_EXTENT_DATA_REF_KEY:
5298c2ecf20Sopenharmony_ci			dref = btrfs_item_ptr(leaf, i,
5308c2ecf20Sopenharmony_ci					      struct btrfs_extent_data_ref);
5318c2ecf20Sopenharmony_ci			ret = add_extent_data_ref(fs_info, leaf, dref, *bytenr,
5328c2ecf20Sopenharmony_ci						  *num_bytes);
5338c2ecf20Sopenharmony_ci			break;
5348c2ecf20Sopenharmony_ci		case BTRFS_SHARED_DATA_REF_KEY:
5358c2ecf20Sopenharmony_ci			sref = btrfs_item_ptr(leaf, i,
5368c2ecf20Sopenharmony_ci					      struct btrfs_shared_data_ref);
5378c2ecf20Sopenharmony_ci			count = btrfs_shared_data_ref_count(leaf, sref);
5388c2ecf20Sopenharmony_ci			ret = add_shared_data_ref(fs_info, key.offset, count,
5398c2ecf20Sopenharmony_ci						  *bytenr, *num_bytes);
5408c2ecf20Sopenharmony_ci			break;
5418c2ecf20Sopenharmony_ci		default:
5428c2ecf20Sopenharmony_ci			break;
5438c2ecf20Sopenharmony_ci		}
5448c2ecf20Sopenharmony_ci		if (ret)
5458c2ecf20Sopenharmony_ci			break;
5468c2ecf20Sopenharmony_ci	}
5478c2ecf20Sopenharmony_ci	return ret;
5488c2ecf20Sopenharmony_ci}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci/* Walk down to the leaf from the given level */
5518c2ecf20Sopenharmony_cistatic int walk_down_tree(struct btrfs_root *root, struct btrfs_path *path,
5528c2ecf20Sopenharmony_ci			  int level, u64 *bytenr, u64 *num_bytes)
5538c2ecf20Sopenharmony_ci{
5548c2ecf20Sopenharmony_ci	struct btrfs_fs_info *fs_info = root->fs_info;
5558c2ecf20Sopenharmony_ci	struct extent_buffer *eb;
5568c2ecf20Sopenharmony_ci	u64 block_bytenr, gen;
5578c2ecf20Sopenharmony_ci	int ret = 0;
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	while (level >= 0) {
5608c2ecf20Sopenharmony_ci		if (level) {
5618c2ecf20Sopenharmony_ci			struct btrfs_key first_key;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci			block_bytenr = btrfs_node_blockptr(path->nodes[level],
5648c2ecf20Sopenharmony_ci							   path->slots[level]);
5658c2ecf20Sopenharmony_ci			gen = btrfs_node_ptr_generation(path->nodes[level],
5668c2ecf20Sopenharmony_ci							path->slots[level]);
5678c2ecf20Sopenharmony_ci			btrfs_node_key_to_cpu(path->nodes[level], &first_key,
5688c2ecf20Sopenharmony_ci					      path->slots[level]);
5698c2ecf20Sopenharmony_ci			eb = read_tree_block(fs_info, block_bytenr, gen,
5708c2ecf20Sopenharmony_ci					     level - 1, &first_key);
5718c2ecf20Sopenharmony_ci			if (IS_ERR(eb))
5728c2ecf20Sopenharmony_ci				return PTR_ERR(eb);
5738c2ecf20Sopenharmony_ci			if (!extent_buffer_uptodate(eb)) {
5748c2ecf20Sopenharmony_ci				free_extent_buffer(eb);
5758c2ecf20Sopenharmony_ci				return -EIO;
5768c2ecf20Sopenharmony_ci			}
5778c2ecf20Sopenharmony_ci			btrfs_tree_read_lock(eb);
5788c2ecf20Sopenharmony_ci			btrfs_set_lock_blocking_read(eb);
5798c2ecf20Sopenharmony_ci			path->nodes[level-1] = eb;
5808c2ecf20Sopenharmony_ci			path->slots[level-1] = 0;
5818c2ecf20Sopenharmony_ci			path->locks[level-1] = BTRFS_READ_LOCK_BLOCKING;
5828c2ecf20Sopenharmony_ci		} else {
5838c2ecf20Sopenharmony_ci			ret = process_leaf(root, path, bytenr, num_bytes);
5848c2ecf20Sopenharmony_ci			if (ret)
5858c2ecf20Sopenharmony_ci				break;
5868c2ecf20Sopenharmony_ci		}
5878c2ecf20Sopenharmony_ci		level--;
5888c2ecf20Sopenharmony_ci	}
5898c2ecf20Sopenharmony_ci	return ret;
5908c2ecf20Sopenharmony_ci}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci/* Walk up to the next node that needs to be processed */
5938c2ecf20Sopenharmony_cistatic int walk_up_tree(struct btrfs_path *path, int *level)
5948c2ecf20Sopenharmony_ci{
5958c2ecf20Sopenharmony_ci	int l;
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	for (l = 0; l < BTRFS_MAX_LEVEL; l++) {
5988c2ecf20Sopenharmony_ci		if (!path->nodes[l])
5998c2ecf20Sopenharmony_ci			continue;
6008c2ecf20Sopenharmony_ci		if (l) {
6018c2ecf20Sopenharmony_ci			path->slots[l]++;
6028c2ecf20Sopenharmony_ci			if (path->slots[l] <
6038c2ecf20Sopenharmony_ci			    btrfs_header_nritems(path->nodes[l])) {
6048c2ecf20Sopenharmony_ci				*level = l;
6058c2ecf20Sopenharmony_ci				return 0;
6068c2ecf20Sopenharmony_ci			}
6078c2ecf20Sopenharmony_ci		}
6088c2ecf20Sopenharmony_ci		btrfs_tree_unlock_rw(path->nodes[l], path->locks[l]);
6098c2ecf20Sopenharmony_ci		free_extent_buffer(path->nodes[l]);
6108c2ecf20Sopenharmony_ci		path->nodes[l] = NULL;
6118c2ecf20Sopenharmony_ci		path->slots[l] = 0;
6128c2ecf20Sopenharmony_ci		path->locks[l] = 0;
6138c2ecf20Sopenharmony_ci	}
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	return 1;
6168c2ecf20Sopenharmony_ci}
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_cistatic void dump_ref_action(struct btrfs_fs_info *fs_info,
6198c2ecf20Sopenharmony_ci			    struct ref_action *ra)
6208c2ecf20Sopenharmony_ci{
6218c2ecf20Sopenharmony_ci	btrfs_err(fs_info,
6228c2ecf20Sopenharmony_ci"  Ref action %d, root %llu, ref_root %llu, parent %llu, owner %llu, offset %llu, num_refs %llu",
6238c2ecf20Sopenharmony_ci		  ra->action, ra->root, ra->ref.root_objectid, ra->ref.parent,
6248c2ecf20Sopenharmony_ci		  ra->ref.owner, ra->ref.offset, ra->ref.num_refs);
6258c2ecf20Sopenharmony_ci	__print_stack_trace(fs_info, ra);
6268c2ecf20Sopenharmony_ci}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci/*
6298c2ecf20Sopenharmony_ci * Dumps all the information from the block entry to printk, it's going to be
6308c2ecf20Sopenharmony_ci * awesome.
6318c2ecf20Sopenharmony_ci */
6328c2ecf20Sopenharmony_cistatic void dump_block_entry(struct btrfs_fs_info *fs_info,
6338c2ecf20Sopenharmony_ci			     struct block_entry *be)
6348c2ecf20Sopenharmony_ci{
6358c2ecf20Sopenharmony_ci	struct ref_entry *ref;
6368c2ecf20Sopenharmony_ci	struct root_entry *re;
6378c2ecf20Sopenharmony_ci	struct ref_action *ra;
6388c2ecf20Sopenharmony_ci	struct rb_node *n;
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	btrfs_err(fs_info,
6418c2ecf20Sopenharmony_ci"dumping block entry [%llu %llu], num_refs %llu, metadata %d, from disk %d",
6428c2ecf20Sopenharmony_ci		  be->bytenr, be->len, be->num_refs, be->metadata,
6438c2ecf20Sopenharmony_ci		  be->from_disk);
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	for (n = rb_first(&be->refs); n; n = rb_next(n)) {
6468c2ecf20Sopenharmony_ci		ref = rb_entry(n, struct ref_entry, node);
6478c2ecf20Sopenharmony_ci		btrfs_err(fs_info,
6488c2ecf20Sopenharmony_ci"  ref root %llu, parent %llu, owner %llu, offset %llu, num_refs %llu",
6498c2ecf20Sopenharmony_ci			  ref->root_objectid, ref->parent, ref->owner,
6508c2ecf20Sopenharmony_ci			  ref->offset, ref->num_refs);
6518c2ecf20Sopenharmony_ci	}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	for (n = rb_first(&be->roots); n; n = rb_next(n)) {
6548c2ecf20Sopenharmony_ci		re = rb_entry(n, struct root_entry, node);
6558c2ecf20Sopenharmony_ci		btrfs_err(fs_info, "  root entry %llu, num_refs %llu",
6568c2ecf20Sopenharmony_ci			  re->root_objectid, re->num_refs);
6578c2ecf20Sopenharmony_ci	}
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	list_for_each_entry(ra, &be->actions, list)
6608c2ecf20Sopenharmony_ci		dump_ref_action(fs_info, ra);
6618c2ecf20Sopenharmony_ci}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci/*
6648c2ecf20Sopenharmony_ci * btrfs_ref_tree_mod: called when we modify a ref for a bytenr
6658c2ecf20Sopenharmony_ci *
6668c2ecf20Sopenharmony_ci * This will add an action item to the given bytenr and do sanity checks to make
6678c2ecf20Sopenharmony_ci * sure we haven't messed something up.  If we are making a new allocation and
6688c2ecf20Sopenharmony_ci * this block entry has history we will delete all previous actions as long as
6698c2ecf20Sopenharmony_ci * our sanity checks pass as they are no longer needed.
6708c2ecf20Sopenharmony_ci */
6718c2ecf20Sopenharmony_ciint btrfs_ref_tree_mod(struct btrfs_fs_info *fs_info,
6728c2ecf20Sopenharmony_ci		       struct btrfs_ref *generic_ref)
6738c2ecf20Sopenharmony_ci{
6748c2ecf20Sopenharmony_ci	struct ref_entry *ref = NULL, *exist;
6758c2ecf20Sopenharmony_ci	struct ref_action *ra = NULL;
6768c2ecf20Sopenharmony_ci	struct block_entry *be = NULL;
6778c2ecf20Sopenharmony_ci	struct root_entry *re = NULL;
6788c2ecf20Sopenharmony_ci	int action = generic_ref->action;
6798c2ecf20Sopenharmony_ci	int ret = 0;
6808c2ecf20Sopenharmony_ci	bool metadata;
6818c2ecf20Sopenharmony_ci	u64 bytenr = generic_ref->bytenr;
6828c2ecf20Sopenharmony_ci	u64 num_bytes = generic_ref->len;
6838c2ecf20Sopenharmony_ci	u64 parent = generic_ref->parent;
6848c2ecf20Sopenharmony_ci	u64 ref_root;
6858c2ecf20Sopenharmony_ci	u64 owner;
6868c2ecf20Sopenharmony_ci	u64 offset;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	if (!btrfs_test_opt(fs_info, REF_VERIFY))
6898c2ecf20Sopenharmony_ci		return 0;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	if (generic_ref->type == BTRFS_REF_METADATA) {
6928c2ecf20Sopenharmony_ci		ref_root = generic_ref->tree_ref.root;
6938c2ecf20Sopenharmony_ci		owner = generic_ref->tree_ref.level;
6948c2ecf20Sopenharmony_ci		offset = 0;
6958c2ecf20Sopenharmony_ci	} else {
6968c2ecf20Sopenharmony_ci		ref_root = generic_ref->data_ref.ref_root;
6978c2ecf20Sopenharmony_ci		owner = generic_ref->data_ref.ino;
6988c2ecf20Sopenharmony_ci		offset = generic_ref->data_ref.offset;
6998c2ecf20Sopenharmony_ci	}
7008c2ecf20Sopenharmony_ci	metadata = owner < BTRFS_FIRST_FREE_OBJECTID;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	ref = kzalloc(sizeof(struct ref_entry), GFP_NOFS);
7038c2ecf20Sopenharmony_ci	ra = kmalloc(sizeof(struct ref_action), GFP_NOFS);
7048c2ecf20Sopenharmony_ci	if (!ra || !ref) {
7058c2ecf20Sopenharmony_ci		kfree(ref);
7068c2ecf20Sopenharmony_ci		kfree(ra);
7078c2ecf20Sopenharmony_ci		ret = -ENOMEM;
7088c2ecf20Sopenharmony_ci		goto out;
7098c2ecf20Sopenharmony_ci	}
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	if (parent) {
7128c2ecf20Sopenharmony_ci		ref->parent = parent;
7138c2ecf20Sopenharmony_ci	} else {
7148c2ecf20Sopenharmony_ci		ref->root_objectid = ref_root;
7158c2ecf20Sopenharmony_ci		ref->owner = owner;
7168c2ecf20Sopenharmony_ci		ref->offset = offset;
7178c2ecf20Sopenharmony_ci	}
7188c2ecf20Sopenharmony_ci	ref->num_refs = (action == BTRFS_DROP_DELAYED_REF) ? -1 : 1;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	memcpy(&ra->ref, ref, sizeof(struct ref_entry));
7218c2ecf20Sopenharmony_ci	/*
7228c2ecf20Sopenharmony_ci	 * Save the extra info from the delayed ref in the ref action to make it
7238c2ecf20Sopenharmony_ci	 * easier to figure out what is happening.  The real ref's we add to the
7248c2ecf20Sopenharmony_ci	 * ref tree need to reflect what we save on disk so it matches any
7258c2ecf20Sopenharmony_ci	 * on-disk refs we pre-loaded.
7268c2ecf20Sopenharmony_ci	 */
7278c2ecf20Sopenharmony_ci	ra->ref.owner = owner;
7288c2ecf20Sopenharmony_ci	ra->ref.offset = offset;
7298c2ecf20Sopenharmony_ci	ra->ref.root_objectid = ref_root;
7308c2ecf20Sopenharmony_ci	__save_stack_trace(ra);
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ra->list);
7338c2ecf20Sopenharmony_ci	ra->action = action;
7348c2ecf20Sopenharmony_ci	ra->root = generic_ref->real_root;
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	/*
7378c2ecf20Sopenharmony_ci	 * This is an allocation, preallocate the block_entry in case we haven't
7388c2ecf20Sopenharmony_ci	 * used it before.
7398c2ecf20Sopenharmony_ci	 */
7408c2ecf20Sopenharmony_ci	ret = -EINVAL;
7418c2ecf20Sopenharmony_ci	if (action == BTRFS_ADD_DELAYED_EXTENT) {
7428c2ecf20Sopenharmony_ci		/*
7438c2ecf20Sopenharmony_ci		 * For subvol_create we'll just pass in whatever the parent root
7448c2ecf20Sopenharmony_ci		 * is and the new root objectid, so let's not treat the passed
7458c2ecf20Sopenharmony_ci		 * in root as if it really has a ref for this bytenr.
7468c2ecf20Sopenharmony_ci		 */
7478c2ecf20Sopenharmony_ci		be = add_block_entry(fs_info, bytenr, num_bytes, ref_root);
7488c2ecf20Sopenharmony_ci		if (IS_ERR(be)) {
7498c2ecf20Sopenharmony_ci			kfree(ref);
7508c2ecf20Sopenharmony_ci			kfree(ra);
7518c2ecf20Sopenharmony_ci			ret = PTR_ERR(be);
7528c2ecf20Sopenharmony_ci			goto out;
7538c2ecf20Sopenharmony_ci		}
7548c2ecf20Sopenharmony_ci		be->num_refs++;
7558c2ecf20Sopenharmony_ci		if (metadata)
7568c2ecf20Sopenharmony_ci			be->metadata = 1;
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci		if (be->num_refs != 1) {
7598c2ecf20Sopenharmony_ci			btrfs_err(fs_info,
7608c2ecf20Sopenharmony_ci			"re-allocated a block that still has references to it!");
7618c2ecf20Sopenharmony_ci			dump_block_entry(fs_info, be);
7628c2ecf20Sopenharmony_ci			dump_ref_action(fs_info, ra);
7638c2ecf20Sopenharmony_ci			kfree(ref);
7648c2ecf20Sopenharmony_ci			kfree(ra);
7658c2ecf20Sopenharmony_ci			goto out_unlock;
7668c2ecf20Sopenharmony_ci		}
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci		while (!list_empty(&be->actions)) {
7698c2ecf20Sopenharmony_ci			struct ref_action *tmp;
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci			tmp = list_first_entry(&be->actions, struct ref_action,
7728c2ecf20Sopenharmony_ci					       list);
7738c2ecf20Sopenharmony_ci			list_del(&tmp->list);
7748c2ecf20Sopenharmony_ci			kfree(tmp);
7758c2ecf20Sopenharmony_ci		}
7768c2ecf20Sopenharmony_ci	} else {
7778c2ecf20Sopenharmony_ci		struct root_entry *tmp;
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci		if (!parent) {
7808c2ecf20Sopenharmony_ci			re = kmalloc(sizeof(struct root_entry), GFP_NOFS);
7818c2ecf20Sopenharmony_ci			if (!re) {
7828c2ecf20Sopenharmony_ci				kfree(ref);
7838c2ecf20Sopenharmony_ci				kfree(ra);
7848c2ecf20Sopenharmony_ci				ret = -ENOMEM;
7858c2ecf20Sopenharmony_ci				goto out;
7868c2ecf20Sopenharmony_ci			}
7878c2ecf20Sopenharmony_ci			/*
7888c2ecf20Sopenharmony_ci			 * This is the root that is modifying us, so it's the
7898c2ecf20Sopenharmony_ci			 * one we want to lookup below when we modify the
7908c2ecf20Sopenharmony_ci			 * re->num_refs.
7918c2ecf20Sopenharmony_ci			 */
7928c2ecf20Sopenharmony_ci			ref_root = generic_ref->real_root;
7938c2ecf20Sopenharmony_ci			re->root_objectid = generic_ref->real_root;
7948c2ecf20Sopenharmony_ci			re->num_refs = 0;
7958c2ecf20Sopenharmony_ci		}
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci		spin_lock(&fs_info->ref_verify_lock);
7988c2ecf20Sopenharmony_ci		be = lookup_block_entry(&fs_info->block_tree, bytenr);
7998c2ecf20Sopenharmony_ci		if (!be) {
8008c2ecf20Sopenharmony_ci			btrfs_err(fs_info,
8018c2ecf20Sopenharmony_ci"trying to do action %d to bytenr %llu num_bytes %llu but there is no existing entry!",
8028c2ecf20Sopenharmony_ci				  action, (unsigned long long)bytenr,
8038c2ecf20Sopenharmony_ci				  (unsigned long long)num_bytes);
8048c2ecf20Sopenharmony_ci			dump_ref_action(fs_info, ra);
8058c2ecf20Sopenharmony_ci			kfree(ref);
8068c2ecf20Sopenharmony_ci			kfree(ra);
8078c2ecf20Sopenharmony_ci			kfree(re);
8088c2ecf20Sopenharmony_ci			goto out_unlock;
8098c2ecf20Sopenharmony_ci		} else if (be->num_refs == 0) {
8108c2ecf20Sopenharmony_ci			btrfs_err(fs_info,
8118c2ecf20Sopenharmony_ci		"trying to do action %d for a bytenr that has 0 total references",
8128c2ecf20Sopenharmony_ci				action);
8138c2ecf20Sopenharmony_ci			dump_block_entry(fs_info, be);
8148c2ecf20Sopenharmony_ci			dump_ref_action(fs_info, ra);
8158c2ecf20Sopenharmony_ci			kfree(ref);
8168c2ecf20Sopenharmony_ci			kfree(ra);
8178c2ecf20Sopenharmony_ci			kfree(re);
8188c2ecf20Sopenharmony_ci			goto out_unlock;
8198c2ecf20Sopenharmony_ci		}
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci		if (!parent) {
8228c2ecf20Sopenharmony_ci			tmp = insert_root_entry(&be->roots, re);
8238c2ecf20Sopenharmony_ci			if (tmp) {
8248c2ecf20Sopenharmony_ci				kfree(re);
8258c2ecf20Sopenharmony_ci				re = tmp;
8268c2ecf20Sopenharmony_ci			}
8278c2ecf20Sopenharmony_ci		}
8288c2ecf20Sopenharmony_ci	}
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	exist = insert_ref_entry(&be->refs, ref);
8318c2ecf20Sopenharmony_ci	if (exist) {
8328c2ecf20Sopenharmony_ci		if (action == BTRFS_DROP_DELAYED_REF) {
8338c2ecf20Sopenharmony_ci			if (exist->num_refs == 0) {
8348c2ecf20Sopenharmony_ci				btrfs_err(fs_info,
8358c2ecf20Sopenharmony_ci"dropping a ref for a existing root that doesn't have a ref on the block");
8368c2ecf20Sopenharmony_ci				dump_block_entry(fs_info, be);
8378c2ecf20Sopenharmony_ci				dump_ref_action(fs_info, ra);
8388c2ecf20Sopenharmony_ci				kfree(ref);
8398c2ecf20Sopenharmony_ci				kfree(ra);
8408c2ecf20Sopenharmony_ci				goto out_unlock;
8418c2ecf20Sopenharmony_ci			}
8428c2ecf20Sopenharmony_ci			exist->num_refs--;
8438c2ecf20Sopenharmony_ci			if (exist->num_refs == 0) {
8448c2ecf20Sopenharmony_ci				rb_erase(&exist->node, &be->refs);
8458c2ecf20Sopenharmony_ci				kfree(exist);
8468c2ecf20Sopenharmony_ci			}
8478c2ecf20Sopenharmony_ci		} else if (!be->metadata) {
8488c2ecf20Sopenharmony_ci			exist->num_refs++;
8498c2ecf20Sopenharmony_ci		} else {
8508c2ecf20Sopenharmony_ci			btrfs_err(fs_info,
8518c2ecf20Sopenharmony_ci"attempting to add another ref for an existing ref on a tree block");
8528c2ecf20Sopenharmony_ci			dump_block_entry(fs_info, be);
8538c2ecf20Sopenharmony_ci			dump_ref_action(fs_info, ra);
8548c2ecf20Sopenharmony_ci			kfree(ref);
8558c2ecf20Sopenharmony_ci			kfree(ra);
8568c2ecf20Sopenharmony_ci			goto out_unlock;
8578c2ecf20Sopenharmony_ci		}
8588c2ecf20Sopenharmony_ci		kfree(ref);
8598c2ecf20Sopenharmony_ci	} else {
8608c2ecf20Sopenharmony_ci		if (action == BTRFS_DROP_DELAYED_REF) {
8618c2ecf20Sopenharmony_ci			btrfs_err(fs_info,
8628c2ecf20Sopenharmony_ci"dropping a ref for a root that doesn't have a ref on the block");
8638c2ecf20Sopenharmony_ci			dump_block_entry(fs_info, be);
8648c2ecf20Sopenharmony_ci			dump_ref_action(fs_info, ra);
8658c2ecf20Sopenharmony_ci			kfree(ref);
8668c2ecf20Sopenharmony_ci			kfree(ra);
8678c2ecf20Sopenharmony_ci			goto out_unlock;
8688c2ecf20Sopenharmony_ci		}
8698c2ecf20Sopenharmony_ci	}
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	if (!parent && !re) {
8728c2ecf20Sopenharmony_ci		re = lookup_root_entry(&be->roots, ref_root);
8738c2ecf20Sopenharmony_ci		if (!re) {
8748c2ecf20Sopenharmony_ci			/*
8758c2ecf20Sopenharmony_ci			 * This shouldn't happen because we will add our re
8768c2ecf20Sopenharmony_ci			 * above when we lookup the be with !parent, but just in
8778c2ecf20Sopenharmony_ci			 * case catch this case so we don't panic because I
8788c2ecf20Sopenharmony_ci			 * didn't think of some other corner case.
8798c2ecf20Sopenharmony_ci			 */
8808c2ecf20Sopenharmony_ci			btrfs_err(fs_info, "failed to find root %llu for %llu",
8818c2ecf20Sopenharmony_ci				  generic_ref->real_root, be->bytenr);
8828c2ecf20Sopenharmony_ci			dump_block_entry(fs_info, be);
8838c2ecf20Sopenharmony_ci			dump_ref_action(fs_info, ra);
8848c2ecf20Sopenharmony_ci			kfree(ra);
8858c2ecf20Sopenharmony_ci			goto out_unlock;
8868c2ecf20Sopenharmony_ci		}
8878c2ecf20Sopenharmony_ci	}
8888c2ecf20Sopenharmony_ci	if (action == BTRFS_DROP_DELAYED_REF) {
8898c2ecf20Sopenharmony_ci		if (re)
8908c2ecf20Sopenharmony_ci			re->num_refs--;
8918c2ecf20Sopenharmony_ci		be->num_refs--;
8928c2ecf20Sopenharmony_ci	} else if (action == BTRFS_ADD_DELAYED_REF) {
8938c2ecf20Sopenharmony_ci		be->num_refs++;
8948c2ecf20Sopenharmony_ci		if (re)
8958c2ecf20Sopenharmony_ci			re->num_refs++;
8968c2ecf20Sopenharmony_ci	}
8978c2ecf20Sopenharmony_ci	list_add_tail(&ra->list, &be->actions);
8988c2ecf20Sopenharmony_ci	ret = 0;
8998c2ecf20Sopenharmony_ciout_unlock:
9008c2ecf20Sopenharmony_ci	spin_unlock(&fs_info->ref_verify_lock);
9018c2ecf20Sopenharmony_ciout:
9028c2ecf20Sopenharmony_ci	if (ret) {
9038c2ecf20Sopenharmony_ci		btrfs_free_ref_cache(fs_info);
9048c2ecf20Sopenharmony_ci		btrfs_clear_opt(fs_info->mount_opt, REF_VERIFY);
9058c2ecf20Sopenharmony_ci	}
9068c2ecf20Sopenharmony_ci	return ret;
9078c2ecf20Sopenharmony_ci}
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci/* Free up the ref cache */
9108c2ecf20Sopenharmony_civoid btrfs_free_ref_cache(struct btrfs_fs_info *fs_info)
9118c2ecf20Sopenharmony_ci{
9128c2ecf20Sopenharmony_ci	struct block_entry *be;
9138c2ecf20Sopenharmony_ci	struct rb_node *n;
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	if (!btrfs_test_opt(fs_info, REF_VERIFY))
9168c2ecf20Sopenharmony_ci		return;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	spin_lock(&fs_info->ref_verify_lock);
9198c2ecf20Sopenharmony_ci	while ((n = rb_first(&fs_info->block_tree))) {
9208c2ecf20Sopenharmony_ci		be = rb_entry(n, struct block_entry, node);
9218c2ecf20Sopenharmony_ci		rb_erase(&be->node, &fs_info->block_tree);
9228c2ecf20Sopenharmony_ci		free_block_entry(be);
9238c2ecf20Sopenharmony_ci		cond_resched_lock(&fs_info->ref_verify_lock);
9248c2ecf20Sopenharmony_ci	}
9258c2ecf20Sopenharmony_ci	spin_unlock(&fs_info->ref_verify_lock);
9268c2ecf20Sopenharmony_ci}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_civoid btrfs_free_ref_tree_range(struct btrfs_fs_info *fs_info, u64 start,
9298c2ecf20Sopenharmony_ci			       u64 len)
9308c2ecf20Sopenharmony_ci{
9318c2ecf20Sopenharmony_ci	struct block_entry *be = NULL, *entry;
9328c2ecf20Sopenharmony_ci	struct rb_node *n;
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	if (!btrfs_test_opt(fs_info, REF_VERIFY))
9358c2ecf20Sopenharmony_ci		return;
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	spin_lock(&fs_info->ref_verify_lock);
9388c2ecf20Sopenharmony_ci	n = fs_info->block_tree.rb_node;
9398c2ecf20Sopenharmony_ci	while (n) {
9408c2ecf20Sopenharmony_ci		entry = rb_entry(n, struct block_entry, node);
9418c2ecf20Sopenharmony_ci		if (entry->bytenr < start) {
9428c2ecf20Sopenharmony_ci			n = n->rb_right;
9438c2ecf20Sopenharmony_ci		} else if (entry->bytenr > start) {
9448c2ecf20Sopenharmony_ci			n = n->rb_left;
9458c2ecf20Sopenharmony_ci		} else {
9468c2ecf20Sopenharmony_ci			be = entry;
9478c2ecf20Sopenharmony_ci			break;
9488c2ecf20Sopenharmony_ci		}
9498c2ecf20Sopenharmony_ci		/* We want to get as close to start as possible */
9508c2ecf20Sopenharmony_ci		if (be == NULL ||
9518c2ecf20Sopenharmony_ci		    (entry->bytenr < start && be->bytenr > start) ||
9528c2ecf20Sopenharmony_ci		    (entry->bytenr < start && entry->bytenr > be->bytenr))
9538c2ecf20Sopenharmony_ci			be = entry;
9548c2ecf20Sopenharmony_ci	}
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	/*
9578c2ecf20Sopenharmony_ci	 * Could have an empty block group, maybe have something to check for
9588c2ecf20Sopenharmony_ci	 * this case to verify we were actually empty?
9598c2ecf20Sopenharmony_ci	 */
9608c2ecf20Sopenharmony_ci	if (!be) {
9618c2ecf20Sopenharmony_ci		spin_unlock(&fs_info->ref_verify_lock);
9628c2ecf20Sopenharmony_ci		return;
9638c2ecf20Sopenharmony_ci	}
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	n = &be->node;
9668c2ecf20Sopenharmony_ci	while (n) {
9678c2ecf20Sopenharmony_ci		be = rb_entry(n, struct block_entry, node);
9688c2ecf20Sopenharmony_ci		n = rb_next(n);
9698c2ecf20Sopenharmony_ci		if (be->bytenr < start && be->bytenr + be->len > start) {
9708c2ecf20Sopenharmony_ci			btrfs_err(fs_info,
9718c2ecf20Sopenharmony_ci				"block entry overlaps a block group [%llu,%llu]!",
9728c2ecf20Sopenharmony_ci				start, len);
9738c2ecf20Sopenharmony_ci			dump_block_entry(fs_info, be);
9748c2ecf20Sopenharmony_ci			continue;
9758c2ecf20Sopenharmony_ci		}
9768c2ecf20Sopenharmony_ci		if (be->bytenr < start)
9778c2ecf20Sopenharmony_ci			continue;
9788c2ecf20Sopenharmony_ci		if (be->bytenr >= start + len)
9798c2ecf20Sopenharmony_ci			break;
9808c2ecf20Sopenharmony_ci		if (be->bytenr + be->len > start + len) {
9818c2ecf20Sopenharmony_ci			btrfs_err(fs_info,
9828c2ecf20Sopenharmony_ci				"block entry overlaps a block group [%llu,%llu]!",
9838c2ecf20Sopenharmony_ci				start, len);
9848c2ecf20Sopenharmony_ci			dump_block_entry(fs_info, be);
9858c2ecf20Sopenharmony_ci		}
9868c2ecf20Sopenharmony_ci		rb_erase(&be->node, &fs_info->block_tree);
9878c2ecf20Sopenharmony_ci		free_block_entry(be);
9888c2ecf20Sopenharmony_ci	}
9898c2ecf20Sopenharmony_ci	spin_unlock(&fs_info->ref_verify_lock);
9908c2ecf20Sopenharmony_ci}
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci/* Walk down all roots and build the ref tree, meant to be called at mount */
9938c2ecf20Sopenharmony_ciint btrfs_build_ref_tree(struct btrfs_fs_info *fs_info)
9948c2ecf20Sopenharmony_ci{
9958c2ecf20Sopenharmony_ci	struct btrfs_path *path;
9968c2ecf20Sopenharmony_ci	struct extent_buffer *eb;
9978c2ecf20Sopenharmony_ci	u64 bytenr = 0, num_bytes = 0;
9988c2ecf20Sopenharmony_ci	int ret, level;
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	if (!btrfs_test_opt(fs_info, REF_VERIFY))
10018c2ecf20Sopenharmony_ci		return 0;
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	path = btrfs_alloc_path();
10048c2ecf20Sopenharmony_ci	if (!path)
10058c2ecf20Sopenharmony_ci		return -ENOMEM;
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	eb = btrfs_read_lock_root_node(fs_info->extent_root);
10088c2ecf20Sopenharmony_ci	btrfs_set_lock_blocking_read(eb);
10098c2ecf20Sopenharmony_ci	level = btrfs_header_level(eb);
10108c2ecf20Sopenharmony_ci	path->nodes[level] = eb;
10118c2ecf20Sopenharmony_ci	path->slots[level] = 0;
10128c2ecf20Sopenharmony_ci	path->locks[level] = BTRFS_READ_LOCK_BLOCKING;
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	while (1) {
10158c2ecf20Sopenharmony_ci		/*
10168c2ecf20Sopenharmony_ci		 * We have to keep track of the bytenr/num_bytes we last hit
10178c2ecf20Sopenharmony_ci		 * because we could have run out of space for an inline ref, and
10188c2ecf20Sopenharmony_ci		 * would have had to added a ref key item which may appear on a
10198c2ecf20Sopenharmony_ci		 * different leaf from the original extent item.
10208c2ecf20Sopenharmony_ci		 */
10218c2ecf20Sopenharmony_ci		ret = walk_down_tree(fs_info->extent_root, path, level,
10228c2ecf20Sopenharmony_ci				     &bytenr, &num_bytes);
10238c2ecf20Sopenharmony_ci		if (ret)
10248c2ecf20Sopenharmony_ci			break;
10258c2ecf20Sopenharmony_ci		ret = walk_up_tree(path, &level);
10268c2ecf20Sopenharmony_ci		if (ret < 0)
10278c2ecf20Sopenharmony_ci			break;
10288c2ecf20Sopenharmony_ci		if (ret > 0) {
10298c2ecf20Sopenharmony_ci			ret = 0;
10308c2ecf20Sopenharmony_ci			break;
10318c2ecf20Sopenharmony_ci		}
10328c2ecf20Sopenharmony_ci	}
10338c2ecf20Sopenharmony_ci	if (ret) {
10348c2ecf20Sopenharmony_ci		btrfs_free_ref_cache(fs_info);
10358c2ecf20Sopenharmony_ci		btrfs_clear_opt(fs_info->mount_opt, REF_VERIFY);
10368c2ecf20Sopenharmony_ci	}
10378c2ecf20Sopenharmony_ci	btrfs_free_path(path);
10388c2ecf20Sopenharmony_ci	return ret;
10398c2ecf20Sopenharmony_ci}
1040