xref: /freebsd/sys/contrib/openzfs/include/sys/zfs_refcount.h (revision 22649d4dba730d46244fd2dff4fd174903c8379f)
1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3  * This file and its contents are supplied under the terms of the
4  * Common Development and Distribution License ("CDDL"), version 1.0.
5  * You may only use this file in accordance with the terms of version
6  * 1.0 of the CDDL.
7  *
8  * A full copy of the text of the CDDL should have accompanied this
9  * source.  A copy of the CDDL is also available via the Internet at
10  * https://opensource.org/license/CDDL-1.0.
11  */
12 /*
13  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
14  * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
15  */
16 
17 #ifndef	_SYS_ZFS_REFCOUNT_H
18 #define	_SYS_ZFS_REFCOUNT_H
19 
20 #include <sys/inttypes.h>
21 #include <sys/avl.h>
22 #include <sys/list.h>
23 #include <sys/zfs_context.h>
24 
25 #ifdef	__cplusplus
26 extern "C" {
27 #endif
28 
29 /*
30  * If the reference is held only by the calling function and not any
31  * particular object, use FTAG (which is a string) for the holder_tag.
32  * Otherwise, use the object that holds the reference.
33  */
34 #define	FTAG ((char *)(uintptr_t)__func__)
35 
36 #ifdef	ZFS_DEBUG
37 typedef struct reference {
38 	union {
39 		avl_node_t a;
40 		list_node_t l;
41 	} ref_link;
42 	const void *ref_holder;
43 	uint64_t ref_number;
44 	boolean_t ref_search;
45 } reference_t;
46 
47 typedef struct refcount {
48 	uint64_t rc_count;
49 	kmutex_t rc_mtx;
50 	avl_tree_t rc_tree;
51 	list_t rc_removed;
52 	uint_t rc_removed_count;
53 	boolean_t rc_tracked;
54 } zfs_refcount_t;
55 
56 /*
57  * Note: zfs_refcount_t must be initialized with
58  * refcount_create[_untracked]()
59  */
60 
61 void zfs_refcount_create(zfs_refcount_t *);
62 void zfs_refcount_create_untracked(zfs_refcount_t *);
63 void zfs_refcount_create_tracked(zfs_refcount_t *);
64 void zfs_refcount_destroy(zfs_refcount_t *);
65 void zfs_refcount_destroy_many(zfs_refcount_t *, uint64_t);
66 int zfs_refcount_is_zero(zfs_refcount_t *);
67 int64_t zfs_refcount_count(zfs_refcount_t *);
68 int64_t zfs_refcount_add(zfs_refcount_t *, const void *);
69 int64_t zfs_refcount_remove(zfs_refcount_t *, const void *);
70 /*
71  * Note that (add|remove)_many adds/removes one reference with "number" N,
72  * _not_ N references with "number" 1, which is what (add|remove)_few does,
73  * or what vanilla zfs_refcount_(add|remove) called N times would do.
74  *
75  * Attempting to remove a reference with number N when none exists is a
76  * panic on debug kernels with reference_tracking enabled.
77  */
78 void zfs_refcount_add_few(zfs_refcount_t *, uint64_t, const void *);
79 void zfs_refcount_remove_few(zfs_refcount_t *, uint64_t, const void *);
80 int64_t zfs_refcount_add_many(zfs_refcount_t *, uint64_t, const void *);
81 int64_t zfs_refcount_remove_many(zfs_refcount_t *, uint64_t, const void *);
82 void zfs_refcount_transfer(zfs_refcount_t *, zfs_refcount_t *);
83 void zfs_refcount_transfer_ownership(zfs_refcount_t *, const void *,
84     const void *);
85 void zfs_refcount_transfer_ownership_many(zfs_refcount_t *, uint64_t,
86     const void *, const void *);
87 boolean_t zfs_refcount_held(zfs_refcount_t *, const void *);
88 boolean_t zfs_refcount_not_held(zfs_refcount_t *, const void *);
89 
90 void zfs_refcount_init(void);
91 void zfs_refcount_fini(void);
92 
93 #else	/* ZFS_DEBUG */
94 
95 typedef struct refcount {
96 	uint64_t rc_count;
97 } zfs_refcount_t;
98 
99 #define	zfs_refcount_create(rc) ((rc)->rc_count = 0)
100 #define	zfs_refcount_create_untracked(rc) ((rc)->rc_count = 0)
101 #define	zfs_refcount_create_tracked(rc) ((rc)->rc_count = 0)
102 #define	zfs_refcount_destroy(rc) ((rc)->rc_count = 0)
103 #define	zfs_refcount_destroy_many(rc, number) ((rc)->rc_count = 0)
104 #define	zfs_refcount_is_zero(rc) (zfs_refcount_count(rc) == 0)
105 #define	zfs_refcount_count(rc) atomic_load_64(&(rc)->rc_count)
106 #define	zfs_refcount_add(rc, holder) atomic_inc_64_nv(&(rc)->rc_count)
107 #define	zfs_refcount_remove(rc, holder) atomic_dec_64_nv(&(rc)->rc_count)
108 #define	zfs_refcount_add_few(rc, number, holder) \
109 	atomic_add_64(&(rc)->rc_count, number)
110 #define	zfs_refcount_remove_few(rc, number, holder) \
111 	atomic_add_64(&(rc)->rc_count, -number)
112 #define	zfs_refcount_add_many(rc, number, holder) \
113 	atomic_add_64_nv(&(rc)->rc_count, number)
114 #define	zfs_refcount_remove_many(rc, number, holder) \
115 	atomic_add_64_nv(&(rc)->rc_count, -number)
116 #define	zfs_refcount_transfer(dst, src) { \
117 	uint64_t __tmp = zfs_refcount_count(src); \
118 	atomic_add_64(&(src)->rc_count, -__tmp); \
119 	atomic_add_64(&(dst)->rc_count, __tmp); \
120 }
121 #define	zfs_refcount_transfer_ownership(rc, ch, nh)		((void)0)
122 #define	zfs_refcount_transfer_ownership_many(rc, nr, ch, nh)	((void)0)
123 #define	zfs_refcount_held(rc, holder)		(zfs_refcount_count(rc) > 0)
124 #define	zfs_refcount_not_held(rc, holder)		(B_TRUE)
125 
126 #define	zfs_refcount_init()
127 #define	zfs_refcount_fini()
128 
129 #endif	/* ZFS_DEBUG */
130 
131 #ifdef	__cplusplus
132 }
133 #endif
134 
135 #endif /* _SYS_REFCOUNT_H */
136