1eda14cbcSMatt Macy /*
2eda14cbcSMatt Macy  * CDDL HEADER START
3eda14cbcSMatt Macy  *
4eda14cbcSMatt Macy  * The contents of this file are subject to the terms of the
5eda14cbcSMatt Macy  * Common Development and Distribution License (the "License").
6eda14cbcSMatt Macy  * You may not use this file except in compliance with the License.
7eda14cbcSMatt Macy  *
8eda14cbcSMatt Macy  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9271171e0SMartin Matuska  * or https://opensource.org/licenses/CDDL-1.0.
10eda14cbcSMatt Macy  * See the License for the specific language governing permissions
11eda14cbcSMatt Macy  * and limitations under the License.
12eda14cbcSMatt Macy  *
13eda14cbcSMatt Macy  * When distributing Covered Code, include this CDDL HEADER in each
14eda14cbcSMatt Macy  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15eda14cbcSMatt Macy  * If applicable, add the following below this CDDL HEADER, with the
16eda14cbcSMatt Macy  * fields enclosed by brackets "[]" replaced with your own identifying
17eda14cbcSMatt Macy  * information: Portions Copyright [yyyy] [name of copyright owner]
18eda14cbcSMatt Macy  *
19eda14cbcSMatt Macy  * CDDL HEADER END
20eda14cbcSMatt Macy  */
21eda14cbcSMatt Macy /*
22eda14cbcSMatt Macy  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23f9693befSMartin Matuska  * Copyright (c) 2012, 2021 by Delphix. All rights reserved.
24eda14cbcSMatt Macy  */
25eda14cbcSMatt Macy 
26eda14cbcSMatt Macy #include <sys/zfs_context.h>
27eda14cbcSMatt Macy #include <sys/zfs_refcount.h>
28eda14cbcSMatt Macy 
29e92ffd9bSMartin Matuska #ifdef	ZFS_DEBUG
30eda14cbcSMatt Macy /*
31eda14cbcSMatt Macy  * Reference count tracking is disabled by default.  It's memory requirements
32eda14cbcSMatt Macy  * are reasonable, however as implemented it consumes a significant amount of
33eda14cbcSMatt Macy  * cpu time.  Until its performance is improved it should be manually enabled.
34eda14cbcSMatt Macy  */
35e92ffd9bSMartin Matuska int reference_tracking_enable = B_FALSE;
36be181ee2SMartin Matuska static uint_t reference_history = 3; /* tunable */
37eda14cbcSMatt Macy 
38eda14cbcSMatt Macy static kmem_cache_t *reference_cache;
39eda14cbcSMatt Macy 
40eda14cbcSMatt Macy void
zfs_refcount_init(void)41eda14cbcSMatt Macy zfs_refcount_init(void)
42eda14cbcSMatt Macy {
43eda14cbcSMatt Macy 	reference_cache = kmem_cache_create("reference_cache",
44eda14cbcSMatt Macy 	    sizeof (reference_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
45eda14cbcSMatt Macy }
46eda14cbcSMatt Macy 
47eda14cbcSMatt Macy void
zfs_refcount_fini(void)48eda14cbcSMatt Macy zfs_refcount_fini(void)
49eda14cbcSMatt Macy {
50eda14cbcSMatt Macy 	kmem_cache_destroy(reference_cache);
51*b7198dcfSMartin Matuska }
52*b7198dcfSMartin Matuska 
53*b7198dcfSMartin Matuska static int
zfs_refcount_compare(const void * x1,const void * x2)54*b7198dcfSMartin Matuska zfs_refcount_compare(const void *x1, const void *x2)
55*b7198dcfSMartin Matuska {
56*b7198dcfSMartin Matuska 	const reference_t *r1 = (const reference_t *)x1;
57*b7198dcfSMartin Matuska 	const reference_t *r2 = (const reference_t *)x2;
58*b7198dcfSMartin Matuska 
59*b7198dcfSMartin Matuska 	int cmp1 = TREE_CMP(r1->ref_holder, r2->ref_holder);
60*b7198dcfSMartin Matuska 	int cmp2 = TREE_CMP(r1->ref_number, r2->ref_number);
61*b7198dcfSMartin Matuska 	int cmp = cmp1 ? cmp1 : cmp2;
62*b7198dcfSMartin Matuska 	return ((cmp || r1->ref_search) ? cmp : TREE_PCMP(r1, r2));
63eda14cbcSMatt Macy }
64eda14cbcSMatt Macy 
65eda14cbcSMatt Macy void
zfs_refcount_create(zfs_refcount_t * rc)66eda14cbcSMatt Macy zfs_refcount_create(zfs_refcount_t *rc)
67eda14cbcSMatt Macy {
68eda14cbcSMatt Macy 	mutex_init(&rc->rc_mtx, NULL, MUTEX_DEFAULT, NULL);
69*b7198dcfSMartin Matuska 	avl_create(&rc->rc_tree, zfs_refcount_compare, sizeof (reference_t),
70*b7198dcfSMartin Matuska 	    offsetof(reference_t, ref_link.a));
71eda14cbcSMatt Macy 	list_create(&rc->rc_removed, sizeof (reference_t),
72*b7198dcfSMartin Matuska 	    offsetof(reference_t, ref_link.l));
73eda14cbcSMatt Macy 	rc->rc_count = 0;
74eda14cbcSMatt Macy 	rc->rc_removed_count = 0;
75eda14cbcSMatt Macy 	rc->rc_tracked = reference_tracking_enable;
76eda14cbcSMatt Macy }
77eda14cbcSMatt Macy 
78eda14cbcSMatt Macy void
zfs_refcount_create_tracked(zfs_refcount_t * rc)79eda14cbcSMatt Macy zfs_refcount_create_tracked(zfs_refcount_t *rc)
80eda14cbcSMatt Macy {
81eda14cbcSMatt Macy 	zfs_refcount_create(rc);
82eda14cbcSMatt Macy 	rc->rc_tracked = B_TRUE;
83eda14cbcSMatt Macy }
84eda14cbcSMatt Macy 
85eda14cbcSMatt Macy void
zfs_refcount_create_untracked(zfs_refcount_t * rc)86eda14cbcSMatt Macy zfs_refcount_create_untracked(zfs_refcount_t *rc)
87eda14cbcSMatt Macy {
88eda14cbcSMatt Macy 	zfs_refcount_create(rc);
89eda14cbcSMatt Macy 	rc->rc_tracked = B_FALSE;
90eda14cbcSMatt Macy }
91eda14cbcSMatt Macy 
92eda14cbcSMatt Macy void
zfs_refcount_destroy_many(zfs_refcount_t * rc,uint64_t number)93eda14cbcSMatt Macy zfs_refcount_destroy_many(zfs_refcount_t *rc, uint64_t number)
94eda14cbcSMatt Macy {
95eda14cbcSMatt Macy 	reference_t *ref;
96*b7198dcfSMartin Matuska 	void *cookie = NULL;
97eda14cbcSMatt Macy 
98eda14cbcSMatt Macy 	ASSERT3U(rc->rc_count, ==, number);
99*b7198dcfSMartin Matuska 	while ((ref = avl_destroy_nodes(&rc->rc_tree, &cookie)) != NULL)
100eda14cbcSMatt Macy 		kmem_cache_free(reference_cache, ref);
101*b7198dcfSMartin Matuska 	avl_destroy(&rc->rc_tree);
102eda14cbcSMatt Macy 
103*b7198dcfSMartin Matuska 	while ((ref = list_remove_head(&rc->rc_removed)))
104eda14cbcSMatt Macy 		kmem_cache_free(reference_cache, ref);
105eda14cbcSMatt Macy 	list_destroy(&rc->rc_removed);
106eda14cbcSMatt Macy 	mutex_destroy(&rc->rc_mtx);
107eda14cbcSMatt Macy }
108eda14cbcSMatt Macy 
109eda14cbcSMatt Macy void
zfs_refcount_destroy(zfs_refcount_t * rc)110eda14cbcSMatt Macy zfs_refcount_destroy(zfs_refcount_t *rc)
111eda14cbcSMatt Macy {
112eda14cbcSMatt Macy 	zfs_refcount_destroy_many(rc, 0);
113eda14cbcSMatt Macy }
114eda14cbcSMatt Macy 
115eda14cbcSMatt Macy int
zfs_refcount_is_zero(zfs_refcount_t * rc)116eda14cbcSMatt Macy zfs_refcount_is_zero(zfs_refcount_t *rc)
117eda14cbcSMatt Macy {
1182faf504dSMartin Matuska 	return (zfs_refcount_count(rc) == 0);
119eda14cbcSMatt Macy }
120eda14cbcSMatt Macy 
121eda14cbcSMatt Macy int64_t
zfs_refcount_count(zfs_refcount_t * rc)122eda14cbcSMatt Macy zfs_refcount_count(zfs_refcount_t *rc)
123eda14cbcSMatt Macy {
1242faf504dSMartin Matuska 	return (atomic_load_64(&rc->rc_count));
125eda14cbcSMatt Macy }
126eda14cbcSMatt Macy 
127eda14cbcSMatt Macy int64_t
zfs_refcount_add_many(zfs_refcount_t * rc,uint64_t number,const void * holder)128eda14cbcSMatt Macy zfs_refcount_add_many(zfs_refcount_t *rc, uint64_t number, const void *holder)
129eda14cbcSMatt Macy {
130*b7198dcfSMartin Matuska 	reference_t *ref;
131eda14cbcSMatt Macy 	int64_t count;
132eda14cbcSMatt Macy 
133*b7198dcfSMartin Matuska 	if (likely(!rc->rc_tracked)) {
1342faf504dSMartin Matuska 		count = atomic_add_64_nv(&(rc)->rc_count, number);
1352faf504dSMartin Matuska 		ASSERT3U(count, >=, number);
1362faf504dSMartin Matuska 		return (count);
1372faf504dSMartin Matuska 	}
1382faf504dSMartin Matuska 
139eda14cbcSMatt Macy 	ref = kmem_cache_alloc(reference_cache, KM_SLEEP);
140eda14cbcSMatt Macy 	ref->ref_holder = holder;
141eda14cbcSMatt Macy 	ref->ref_number = number;
142*b7198dcfSMartin Matuska 	ref->ref_search = B_FALSE;
143eda14cbcSMatt Macy 	mutex_enter(&rc->rc_mtx);
144*b7198dcfSMartin Matuska 	avl_add(&rc->rc_tree, ref);
145eda14cbcSMatt Macy 	rc->rc_count += number;
146eda14cbcSMatt Macy 	count = rc->rc_count;
147eda14cbcSMatt Macy 	mutex_exit(&rc->rc_mtx);
148eda14cbcSMatt Macy 
149eda14cbcSMatt Macy 	return (count);
150eda14cbcSMatt Macy }
151eda14cbcSMatt Macy 
152eda14cbcSMatt Macy int64_t
zfs_refcount_add(zfs_refcount_t * rc,const void * holder)153eda14cbcSMatt Macy zfs_refcount_add(zfs_refcount_t *rc, const void *holder)
154eda14cbcSMatt Macy {
155eda14cbcSMatt Macy 	return (zfs_refcount_add_many(rc, 1, holder));
156eda14cbcSMatt Macy }
157eda14cbcSMatt Macy 
1584e8d558cSMartin Matuska void
zfs_refcount_add_few(zfs_refcount_t * rc,uint64_t number,const void * holder)1594e8d558cSMartin Matuska zfs_refcount_add_few(zfs_refcount_t *rc, uint64_t number, const void *holder)
1604e8d558cSMartin Matuska {
161*b7198dcfSMartin Matuska 	if (likely(!rc->rc_tracked))
1624e8d558cSMartin Matuska 		(void) zfs_refcount_add_many(rc, number, holder);
1634e8d558cSMartin Matuska 	else for (; number > 0; number--)
1644e8d558cSMartin Matuska 		(void) zfs_refcount_add(rc, holder);
1654e8d558cSMartin Matuska }
1664e8d558cSMartin Matuska 
167eda14cbcSMatt Macy int64_t
zfs_refcount_remove_many(zfs_refcount_t * rc,uint64_t number,const void * holder)168eda14cbcSMatt Macy zfs_refcount_remove_many(zfs_refcount_t *rc, uint64_t number,
169eda14cbcSMatt Macy     const void *holder)
170eda14cbcSMatt Macy {
171*b7198dcfSMartin Matuska 	reference_t *ref, s;
172eda14cbcSMatt Macy 	int64_t count;
173eda14cbcSMatt Macy 
174*b7198dcfSMartin Matuska 	if (likely(!rc->rc_tracked)) {
1752faf504dSMartin Matuska 		count = atomic_add_64_nv(&(rc)->rc_count, -number);
1762faf504dSMartin Matuska 		ASSERT3S(count, >=, 0);
177eda14cbcSMatt Macy 		return (count);
178eda14cbcSMatt Macy 	}
179eda14cbcSMatt Macy 
180*b7198dcfSMartin Matuska 	s.ref_holder = holder;
181*b7198dcfSMartin Matuska 	s.ref_number = number;
182*b7198dcfSMartin Matuska 	s.ref_search = B_TRUE;
1832faf504dSMartin Matuska 	mutex_enter(&rc->rc_mtx);
1842faf504dSMartin Matuska 	ASSERT3U(rc->rc_count, >=, number);
185*b7198dcfSMartin Matuska 	ref = avl_find(&rc->rc_tree, &s, NULL);
186*b7198dcfSMartin Matuska 	if (unlikely(ref == NULL)) {
187*b7198dcfSMartin Matuska 		panic("No such hold %p on refcount %llx", holder,
188*b7198dcfSMartin Matuska 		    (u_longlong_t)(uintptr_t)rc);
189*b7198dcfSMartin Matuska 		return (-1);
190*b7198dcfSMartin Matuska 	}
191*b7198dcfSMartin Matuska 	avl_remove(&rc->rc_tree, ref);
192eda14cbcSMatt Macy 	if (reference_history > 0) {
193eda14cbcSMatt Macy 		list_insert_head(&rc->rc_removed, ref);
194*b7198dcfSMartin Matuska 		if (rc->rc_removed_count >= reference_history) {
195*b7198dcfSMartin Matuska 			ref = list_remove_tail(&rc->rc_removed);
196eda14cbcSMatt Macy 			kmem_cache_free(reference_cache, ref);
197*b7198dcfSMartin Matuska 		} else {
198*b7198dcfSMartin Matuska 			rc->rc_removed_count++;
199eda14cbcSMatt Macy 		}
200eda14cbcSMatt Macy 	} else {
201eda14cbcSMatt Macy 		kmem_cache_free(reference_cache, ref);
202eda14cbcSMatt Macy 	}
203eda14cbcSMatt Macy 	rc->rc_count -= number;
204eda14cbcSMatt Macy 	count = rc->rc_count;
205eda14cbcSMatt Macy 	mutex_exit(&rc->rc_mtx);
206eda14cbcSMatt Macy 	return (count);
207eda14cbcSMatt Macy }
208eda14cbcSMatt Macy 
209eda14cbcSMatt Macy int64_t
zfs_refcount_remove(zfs_refcount_t * rc,const void * holder)210eda14cbcSMatt Macy zfs_refcount_remove(zfs_refcount_t *rc, const void *holder)
211eda14cbcSMatt Macy {
212eda14cbcSMatt Macy 	return (zfs_refcount_remove_many(rc, 1, holder));
213eda14cbcSMatt Macy }
214eda14cbcSMatt Macy 
215eda14cbcSMatt Macy void
zfs_refcount_remove_few(zfs_refcount_t * rc,uint64_t number,const void * holder)2164e8d558cSMartin Matuska zfs_refcount_remove_few(zfs_refcount_t *rc, uint64_t number, const void *holder)
2174e8d558cSMartin Matuska {
218*b7198dcfSMartin Matuska 	if (likely(!rc->rc_tracked))
2194e8d558cSMartin Matuska 		(void) zfs_refcount_remove_many(rc, number, holder);
2204e8d558cSMartin Matuska 	else for (; number > 0; number--)
2214e8d558cSMartin Matuska 		(void) zfs_refcount_remove(rc, holder);
2224e8d558cSMartin Matuska }
2234e8d558cSMartin Matuska 
2244e8d558cSMartin Matuska void
zfs_refcount_transfer(zfs_refcount_t * dst,zfs_refcount_t * src)225eda14cbcSMatt Macy zfs_refcount_transfer(zfs_refcount_t *dst, zfs_refcount_t *src)
226eda14cbcSMatt Macy {
227*b7198dcfSMartin Matuska 	avl_tree_t tree;
228*b7198dcfSMartin Matuska 	list_t removed;
229*b7198dcfSMartin Matuska 	reference_t *ref;
230*b7198dcfSMartin Matuska 	void *cookie = NULL;
231*b7198dcfSMartin Matuska 	uint64_t count;
232*b7198dcfSMartin Matuska 	uint_t removed_count;
233eda14cbcSMatt Macy 
234*b7198dcfSMartin Matuska 	avl_create(&tree, zfs_refcount_compare, sizeof (reference_t),
235*b7198dcfSMartin Matuska 	    offsetof(reference_t, ref_link.a));
236eda14cbcSMatt Macy 	list_create(&removed, sizeof (reference_t),
237*b7198dcfSMartin Matuska 	    offsetof(reference_t, ref_link.l));
238eda14cbcSMatt Macy 
239eda14cbcSMatt Macy 	mutex_enter(&src->rc_mtx);
240eda14cbcSMatt Macy 	count = src->rc_count;
241eda14cbcSMatt Macy 	removed_count = src->rc_removed_count;
242eda14cbcSMatt Macy 	src->rc_count = 0;
243eda14cbcSMatt Macy 	src->rc_removed_count = 0;
244*b7198dcfSMartin Matuska 	avl_swap(&tree, &src->rc_tree);
245eda14cbcSMatt Macy 	list_move_tail(&removed, &src->rc_removed);
246eda14cbcSMatt Macy 	mutex_exit(&src->rc_mtx);
247eda14cbcSMatt Macy 
248eda14cbcSMatt Macy 	mutex_enter(&dst->rc_mtx);
249eda14cbcSMatt Macy 	dst->rc_count += count;
250eda14cbcSMatt Macy 	dst->rc_removed_count += removed_count;
251*b7198dcfSMartin Matuska 	if (avl_is_empty(&dst->rc_tree))
252*b7198dcfSMartin Matuska 		avl_swap(&dst->rc_tree, &tree);
253*b7198dcfSMartin Matuska 	else while ((ref = avl_destroy_nodes(&tree, &cookie)) != NULL)
254*b7198dcfSMartin Matuska 		avl_add(&dst->rc_tree, ref);
255eda14cbcSMatt Macy 	list_move_tail(&dst->rc_removed, &removed);
256eda14cbcSMatt Macy 	mutex_exit(&dst->rc_mtx);
257eda14cbcSMatt Macy 
258*b7198dcfSMartin Matuska 	avl_destroy(&tree);
259eda14cbcSMatt Macy 	list_destroy(&removed);
260eda14cbcSMatt Macy }
261eda14cbcSMatt Macy 
262eda14cbcSMatt Macy void
zfs_refcount_transfer_ownership_many(zfs_refcount_t * rc,uint64_t number,const void * current_holder,const void * new_holder)263eda14cbcSMatt Macy zfs_refcount_transfer_ownership_many(zfs_refcount_t *rc, uint64_t number,
264eda14cbcSMatt Macy     const void *current_holder, const void *new_holder)
265eda14cbcSMatt Macy {
266*b7198dcfSMartin Matuska 	reference_t *ref, s;
267eda14cbcSMatt Macy 
268*b7198dcfSMartin Matuska 	if (likely(!rc->rc_tracked))
269eda14cbcSMatt Macy 		return;
270eda14cbcSMatt Macy 
271*b7198dcfSMartin Matuska 	s.ref_holder = current_holder;
272*b7198dcfSMartin Matuska 	s.ref_number = number;
273*b7198dcfSMartin Matuska 	s.ref_search = B_TRUE;
2742faf504dSMartin Matuska 	mutex_enter(&rc->rc_mtx);
275*b7198dcfSMartin Matuska 	ref = avl_find(&rc->rc_tree, &s, NULL);
276*b7198dcfSMartin Matuska 	ASSERT(ref);
277eda14cbcSMatt Macy 	ref->ref_holder = new_holder;
278*b7198dcfSMartin Matuska 	avl_update(&rc->rc_tree, ref);
279eda14cbcSMatt Macy 	mutex_exit(&rc->rc_mtx);
280eda14cbcSMatt Macy }
281eda14cbcSMatt Macy 
282eda14cbcSMatt Macy void
zfs_refcount_transfer_ownership(zfs_refcount_t * rc,const void * current_holder,const void * new_holder)283eda14cbcSMatt Macy zfs_refcount_transfer_ownership(zfs_refcount_t *rc, const void *current_holder,
284eda14cbcSMatt Macy     const void *new_holder)
285eda14cbcSMatt Macy {
286eda14cbcSMatt Macy 	return (zfs_refcount_transfer_ownership_many(rc, 1, current_holder,
287eda14cbcSMatt Macy 	    new_holder));
288eda14cbcSMatt Macy }
289eda14cbcSMatt Macy 
290eda14cbcSMatt Macy /*
291eda14cbcSMatt Macy  * If tracking is enabled, return true if a reference exists that matches
292eda14cbcSMatt Macy  * the "holder" tag. If tracking is disabled, then return true if a reference
293eda14cbcSMatt Macy  * might be held.
294eda14cbcSMatt Macy  */
295eda14cbcSMatt Macy boolean_t
zfs_refcount_held(zfs_refcount_t * rc,const void * holder)296eda14cbcSMatt Macy zfs_refcount_held(zfs_refcount_t *rc, const void *holder)
297eda14cbcSMatt Macy {
298*b7198dcfSMartin Matuska 	reference_t *ref, s;
299*b7198dcfSMartin Matuska 	avl_index_t idx;
300*b7198dcfSMartin Matuska 	boolean_t res;
301eda14cbcSMatt Macy 
302*b7198dcfSMartin Matuska 	if (likely(!rc->rc_tracked))
3032faf504dSMartin Matuska 		return (zfs_refcount_count(rc) > 0);
3042faf504dSMartin Matuska 
305*b7198dcfSMartin Matuska 	s.ref_holder = holder;
306*b7198dcfSMartin Matuska 	s.ref_number = 0;
307*b7198dcfSMartin Matuska 	s.ref_search = B_TRUE;
308eda14cbcSMatt Macy 	mutex_enter(&rc->rc_mtx);
309*b7198dcfSMartin Matuska 	ref = avl_find(&rc->rc_tree, &s, &idx);
310*b7198dcfSMartin Matuska 	if (likely(ref == NULL))
311*b7198dcfSMartin Matuska 		ref = avl_nearest(&rc->rc_tree, idx, AVL_AFTER);
312*b7198dcfSMartin Matuska 	res = ref && ref->ref_holder == holder;
313eda14cbcSMatt Macy 	mutex_exit(&rc->rc_mtx);
314*b7198dcfSMartin Matuska 	return (res);
315eda14cbcSMatt Macy }
316eda14cbcSMatt Macy 
317eda14cbcSMatt Macy /*
318eda14cbcSMatt Macy  * If tracking is enabled, return true if a reference does not exist that
319eda14cbcSMatt Macy  * matches the "holder" tag. If tracking is disabled, always return true
320eda14cbcSMatt Macy  * since the reference might not be held.
321eda14cbcSMatt Macy  */
322eda14cbcSMatt Macy boolean_t
zfs_refcount_not_held(zfs_refcount_t * rc,const void * holder)323eda14cbcSMatt Macy zfs_refcount_not_held(zfs_refcount_t *rc, const void *holder)
324eda14cbcSMatt Macy {
325*b7198dcfSMartin Matuska 	reference_t *ref, s;
326*b7198dcfSMartin Matuska 	avl_index_t idx;
327*b7198dcfSMartin Matuska 	boolean_t res;
328eda14cbcSMatt Macy 
329*b7198dcfSMartin Matuska 	if (likely(!rc->rc_tracked))
330eda14cbcSMatt Macy 		return (B_TRUE);
331eda14cbcSMatt Macy 
3322faf504dSMartin Matuska 	mutex_enter(&rc->rc_mtx);
333*b7198dcfSMartin Matuska 	s.ref_holder = holder;
334*b7198dcfSMartin Matuska 	s.ref_number = 0;
335*b7198dcfSMartin Matuska 	s.ref_search = B_TRUE;
336*b7198dcfSMartin Matuska 	ref = avl_find(&rc->rc_tree, &s, &idx);
337*b7198dcfSMartin Matuska 	if (likely(ref == NULL))
338*b7198dcfSMartin Matuska 		ref = avl_nearest(&rc->rc_tree, idx, AVL_AFTER);
339*b7198dcfSMartin Matuska 	res = ref == NULL || ref->ref_holder != holder;
340eda14cbcSMatt Macy 	mutex_exit(&rc->rc_mtx);
341*b7198dcfSMartin Matuska 	return (res);
342eda14cbcSMatt Macy }
343f9693befSMartin Matuska 
3446ba2210eSMartin Matuska EXPORT_SYMBOL(zfs_refcount_create);
3456ba2210eSMartin Matuska EXPORT_SYMBOL(zfs_refcount_destroy);
3466ba2210eSMartin Matuska EXPORT_SYMBOL(zfs_refcount_is_zero);
3476ba2210eSMartin Matuska EXPORT_SYMBOL(zfs_refcount_count);
3486ba2210eSMartin Matuska EXPORT_SYMBOL(zfs_refcount_add);
3496ba2210eSMartin Matuska EXPORT_SYMBOL(zfs_refcount_remove);
3506ba2210eSMartin Matuska EXPORT_SYMBOL(zfs_refcount_held);
3516ba2210eSMartin Matuska 
352f9693befSMartin Matuska /* BEGIN CSTYLED */
353f9693befSMartin Matuska ZFS_MODULE_PARAM(zfs, , reference_tracking_enable, INT, ZMOD_RW,
354f9693befSMartin Matuska 	"Track reference holders to refcount_t objects");
355f9693befSMartin Matuska 
356be181ee2SMartin Matuska ZFS_MODULE_PARAM(zfs, , reference_history, UINT, ZMOD_RW,
357f9693befSMartin Matuska 	"Maximum reference holders being tracked");
358f9693befSMartin Matuska /* END CSTYLED */
359eda14cbcSMatt Macy #endif	/* ZFS_DEBUG */
360