xref: /illumos-gate/usr/src/uts/common/fs/zfs/sys/refcount.h (revision 9b9d39d2a32ff806d2431dbcc50968ef1e6d46b2)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
24  */
25 
26 #ifndef	_SYS_REFCOUNT_H
27 #define	_SYS_REFCOUNT_H
28 
29 #include <sys/inttypes.h>
30 #include <sys/avl.h>
31 #include <sys/list.h>
32 #include <sys/zfs_context.h>
33 
34 #ifdef	__cplusplus
35 extern "C" {
36 #endif
37 
38 /*
39  * If the reference is held only by the calling function and not any
40  * particular object, use FTAG (which is a string) for the holder_tag.
41  * Otherwise, use the object that holds the reference.
42  */
43 #define	FTAG ((char *)(uintptr_t)__func__)
44 
45 #define	atomic_load_64(v) (*(volatile uint64_t *)(v))
46 
47 #ifdef	ZFS_DEBUG
48 typedef struct reference {
49 	union {
50 		avl_node_t a;
51 		list_node_t l;
52 	} ref_link;
53 	const void *ref_holder;
54 	uint8_t *ref_removed;
55 	uint64_t ref_number;
56 	boolean_t ref_search;
57 } reference_t;
58 
59 typedef struct refcount {
60 	uint64_t rc_count;
61 	kmutex_t rc_mtx;
62 	avl_tree_t rc_tree;
63 	list_t rc_removed;
64 	uint_t rc_removed_count;
65 	boolean_t rc_tracked;
66 } zfs_refcount_t;
67 
68 /*
69  * Note: zfs_refcount_t must be initialized with
70  * refcount_create[_untracked]()
71  */
72 
73 void zfs_refcount_create(zfs_refcount_t *);
74 void zfs_refcount_create_untracked(zfs_refcount_t *);
75 void zfs_refcount_create_tracked(zfs_refcount_t *);
76 void zfs_refcount_destroy(zfs_refcount_t *);
77 void zfs_refcount_destroy_many(zfs_refcount_t *, uint64_t);
78 int zfs_refcount_is_zero(zfs_refcount_t *);
79 int64_t zfs_refcount_count(zfs_refcount_t *);
80 int64_t zfs_refcount_add(zfs_refcount_t *, const void *);
81 int64_t zfs_refcount_remove(zfs_refcount_t *, const void *);
82 /*
83  * Note that (add|remove)_many adds/removes one reference with "number" N,
84  * _not_ N references with "number" 1, which is what (add|remove)_few does,
85  * or what vanilla zfs_refcount_(add|remove) called N times would do.
86  *
87  * That is, add_many should be used to add N references at once when they will
88  * subsequently be removed together via a call to remove_many. And they must be
89  * -- attempting to remove a reference with number N when none exists is a
90  * panic on debug kernels with reference_tracking enabled.
91  *
92  * add_few should be used to add N references at once when they may be removed
93  * again piecemeal, via multiple calls to remove and remove_few.
94  */
95 void zfs_refcount_add_few(zfs_refcount_t *, uint64_t, const void *);
96 void zfs_refcount_remove_few(zfs_refcount_t *, uint64_t, const void *);
97 int64_t zfs_refcount_add_many(zfs_refcount_t *, uint64_t, const void *);
98 int64_t zfs_refcount_remove_many(zfs_refcount_t *, uint64_t, const void *);
99 void zfs_refcount_transfer(zfs_refcount_t *, zfs_refcount_t *);
100 void zfs_refcount_transfer_ownership(zfs_refcount_t *, const void *,
101     const void *);
102 void zfs_refcount_transfer_ownership_many(zfs_refcount_t *, uint64_t,
103     const void *, const void *);
104 boolean_t zfs_refcount_held(zfs_refcount_t *, const void *);
105 boolean_t zfs_refcount_not_held(zfs_refcount_t *, const void *);
106 
107 void zfs_refcount_init(void);
108 void zfs_refcount_fini(void);
109 
110 #else	/* ZFS_DEBUG */
111 
112 typedef struct refcount {
113 	uint64_t rc_count;
114 } zfs_refcount_t;
115 
116 #define	zfs_refcount_create(rc) ((rc)->rc_count = 0)
117 #define	zfs_refcount_create_untracked(rc) ((rc)->rc_count = 0)
118 #define	zfs_refcount_create_tracked(rc) ((rc)->rc_count = 0)
119 #define	zfs_refcount_destroy(rc) ((rc)->rc_count = 0)
120 #define	zfs_refcount_destroy_many(rc, number) ((rc)->rc_count = 0)
121 #define	zfs_refcount_is_zero(rc) (zfs_refcount_count(rc) == 0)
122 #define	zfs_refcount_count(rc) atomic_load_64(&(rc)->rc_count)
123 #define	zfs_refcount_add(rc, holder) atomic_inc_64_nv(&(rc)->rc_count)
124 #define	zfs_refcount_remove(rc, holder) atomic_dec_64_nv(&(rc)->rc_count)
125 #define	zfs_refcount_add_few(rc, number, holder) \
126 	atomic_add_64(&(rc)->rc_count, number)
127 #define	zfs_refcount_remove_few(rc, number, holder) \
128 	atomic_add_64(&(rc)->rc_count, -number)
129 #define	zfs_refcount_add_many(rc, number, holder) \
130 	atomic_add_64_nv(&(rc)->rc_count, number)
131 #define	zfs_refcount_remove_many(rc, number, holder) \
132 	atomic_add_64_nv(&(rc)->rc_count, -number)
133 #define	zfs_refcount_transfer(dst, src) { \
134 	uint64_t __tmp = zfs_refcount_count(src); \
135 	atomic_add_64(&(src)->rc_count, -__tmp); \
136 	atomic_add_64(&(dst)->rc_count, __tmp); \
137 }
138 #define	zfs_refcount_transfer_ownership(rc, ch, nh)		((void)0)
139 #define	zfs_refcount_transfer_ownership_many(rc, nr, ch, nh)	((void)0)
140 #define	zfs_refcount_held(rc, holder)		(zfs_refcount_count(rc) > 0)
141 #define	zfs_refcount_not_held(rc, holder)		(B_TRUE)
142 
143 #define	zfs_refcount_init()
144 #define	zfs_refcount_fini()
145 
146 #endif	/* ZFS_DEBUG */
147 
148 #ifdef	__cplusplus
149 }
150 #endif
151 
152 #endif /* _SYS_REFCOUNT_H */
153