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