1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5*91ebeef5Sahrens * Common Development and Distribution License (the "License"). 6*91ebeef5Sahrens * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 21fa9e4066Sahrens /* 22*91ebeef5Sahrens * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23fa9e4066Sahrens * Use is subject to license terms. 24fa9e4066Sahrens */ 25fa9e4066Sahrens 26fa9e4066Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27fa9e4066Sahrens 28fa9e4066Sahrens #include <sys/zfs_context.h> 29fa9e4066Sahrens #include <sys/refcount.h> 30fa9e4066Sahrens 31fa9e4066Sahrens #if defined(DEBUG) || !defined(_KERNEL) 32fa9e4066Sahrens 33fa9e4066Sahrens #ifdef _KERNEL 34fa9e4066Sahrens int reference_tracking_enable = FALSE; /* runs out of memory too easily */ 35fa9e4066Sahrens #else 36fa9e4066Sahrens int reference_tracking_enable = TRUE; 37fa9e4066Sahrens #endif 38fa9e4066Sahrens int reference_history = 4; /* tunable */ 39fa9e4066Sahrens 40fa9e4066Sahrens static kmem_cache_t *reference_cache; 41fa9e4066Sahrens static kmem_cache_t *reference_history_cache; 42fa9e4066Sahrens 43fa9e4066Sahrens void 44fa9e4066Sahrens refcount_init(void) 45fa9e4066Sahrens { 46fa9e4066Sahrens reference_cache = kmem_cache_create("reference_cache", 47fa9e4066Sahrens sizeof (reference_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 48fa9e4066Sahrens 49fa9e4066Sahrens reference_history_cache = kmem_cache_create("reference_history_cache", 50fa9e4066Sahrens sizeof (uint64_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 51fa9e4066Sahrens } 52fa9e4066Sahrens 53fa9e4066Sahrens void 54fa9e4066Sahrens refcount_fini(void) 55fa9e4066Sahrens { 56fa9e4066Sahrens kmem_cache_destroy(reference_cache); 57fa9e4066Sahrens kmem_cache_destroy(reference_history_cache); 58fa9e4066Sahrens } 59fa9e4066Sahrens 60fa9e4066Sahrens void 61fa9e4066Sahrens refcount_create(refcount_t *rc) 62fa9e4066Sahrens { 63*91ebeef5Sahrens mutex_init(&rc->rc_mtx, NULL, MUTEX_DEFAULT, NULL); 64fa9e4066Sahrens list_create(&rc->rc_list, sizeof (reference_t), 65fa9e4066Sahrens offsetof(reference_t, ref_link)); 66fa9e4066Sahrens list_create(&rc->rc_removed, sizeof (reference_t), 67fa9e4066Sahrens offsetof(reference_t, ref_link)); 68*91ebeef5Sahrens rc->rc_count = 0; 69*91ebeef5Sahrens rc->rc_removed_count = 0; 70fa9e4066Sahrens } 71fa9e4066Sahrens 72fa9e4066Sahrens void 73fa9e4066Sahrens refcount_destroy_many(refcount_t *rc, uint64_t number) 74fa9e4066Sahrens { 75fa9e4066Sahrens reference_t *ref; 76fa9e4066Sahrens 77fa9e4066Sahrens ASSERT(rc->rc_count == number); 78fa9e4066Sahrens while (ref = list_head(&rc->rc_list)) { 79fa9e4066Sahrens list_remove(&rc->rc_list, ref); 80fa9e4066Sahrens kmem_cache_free(reference_cache, ref); 81fa9e4066Sahrens } 82fa9e4066Sahrens list_destroy(&rc->rc_list); 83fa9e4066Sahrens 84fa9e4066Sahrens while (ref = list_head(&rc->rc_removed)) { 85fa9e4066Sahrens list_remove(&rc->rc_removed, ref); 86fa9e4066Sahrens kmem_cache_free(reference_history_cache, ref->ref_removed); 87fa9e4066Sahrens kmem_cache_free(reference_cache, ref); 88fa9e4066Sahrens } 89fa9e4066Sahrens list_destroy(&rc->rc_removed); 90fa9e4066Sahrens mutex_destroy(&rc->rc_mtx); 91fa9e4066Sahrens } 92fa9e4066Sahrens 93fa9e4066Sahrens void 94fa9e4066Sahrens refcount_destroy(refcount_t *rc) 95fa9e4066Sahrens { 96fa9e4066Sahrens refcount_destroy_many(rc, 0); 97fa9e4066Sahrens } 98fa9e4066Sahrens 99fa9e4066Sahrens int 100fa9e4066Sahrens refcount_is_zero(refcount_t *rc) 101fa9e4066Sahrens { 102fa9e4066Sahrens ASSERT(rc->rc_count >= 0); 103fa9e4066Sahrens return (rc->rc_count == 0); 104fa9e4066Sahrens } 105fa9e4066Sahrens 106fa9e4066Sahrens int64_t 107fa9e4066Sahrens refcount_count(refcount_t *rc) 108fa9e4066Sahrens { 109fa9e4066Sahrens ASSERT(rc->rc_count >= 0); 110fa9e4066Sahrens return (rc->rc_count); 111fa9e4066Sahrens } 112fa9e4066Sahrens 113fa9e4066Sahrens int64_t 114fa9e4066Sahrens refcount_add_many(refcount_t *rc, uint64_t number, void *holder) 115fa9e4066Sahrens { 116fa9e4066Sahrens reference_t *ref; 117fa9e4066Sahrens int64_t count; 118fa9e4066Sahrens 119fa9e4066Sahrens if (reference_tracking_enable) { 120fa9e4066Sahrens ref = kmem_cache_alloc(reference_cache, KM_SLEEP); 121fa9e4066Sahrens ref->ref_holder = holder; 122fa9e4066Sahrens ref->ref_number = number; 123fa9e4066Sahrens } 124fa9e4066Sahrens mutex_enter(&rc->rc_mtx); 125fa9e4066Sahrens ASSERT(rc->rc_count >= 0); 126fa9e4066Sahrens if (reference_tracking_enable) 127fa9e4066Sahrens list_insert_head(&rc->rc_list, ref); 128fa9e4066Sahrens rc->rc_count += number; 129fa9e4066Sahrens count = rc->rc_count; 130fa9e4066Sahrens mutex_exit(&rc->rc_mtx); 131fa9e4066Sahrens 132fa9e4066Sahrens return (count); 133fa9e4066Sahrens } 134fa9e4066Sahrens 135fa9e4066Sahrens int64_t 136fa9e4066Sahrens refcount_add(refcount_t *rc, void *holder) 137fa9e4066Sahrens { 138fa9e4066Sahrens return (refcount_add_many(rc, 1, holder)); 139fa9e4066Sahrens } 140fa9e4066Sahrens 141fa9e4066Sahrens int64_t 142fa9e4066Sahrens refcount_remove_many(refcount_t *rc, uint64_t number, void *holder) 143fa9e4066Sahrens { 144fa9e4066Sahrens reference_t *ref; 145fa9e4066Sahrens int64_t count; 146fa9e4066Sahrens 147fa9e4066Sahrens mutex_enter(&rc->rc_mtx); 148fa9e4066Sahrens ASSERT(rc->rc_count >= number); 149fa9e4066Sahrens 150fa9e4066Sahrens if (!reference_tracking_enable) { 151fa9e4066Sahrens rc->rc_count -= number; 152fa9e4066Sahrens count = rc->rc_count; 153fa9e4066Sahrens mutex_exit(&rc->rc_mtx); 154fa9e4066Sahrens return (count); 155fa9e4066Sahrens } 156fa9e4066Sahrens 157fa9e4066Sahrens for (ref = list_head(&rc->rc_list); ref; 158fa9e4066Sahrens ref = list_next(&rc->rc_list, ref)) { 159fa9e4066Sahrens if (ref->ref_holder == holder && ref->ref_number == number) { 160fa9e4066Sahrens list_remove(&rc->rc_list, ref); 161fa9e4066Sahrens if (reference_history > 0) { 162fa9e4066Sahrens ref->ref_removed = 163fa9e4066Sahrens kmem_cache_alloc(reference_history_cache, 164fa9e4066Sahrens KM_SLEEP); 165fa9e4066Sahrens list_insert_head(&rc->rc_removed, ref); 166fa9e4066Sahrens rc->rc_removed_count++; 167fa9e4066Sahrens if (rc->rc_removed_count >= reference_history) { 168fa9e4066Sahrens ref = list_tail(&rc->rc_removed); 169fa9e4066Sahrens list_remove(&rc->rc_removed, ref); 170fa9e4066Sahrens kmem_cache_free(reference_history_cache, 171fa9e4066Sahrens ref->ref_removed); 172fa9e4066Sahrens kmem_cache_free(reference_cache, ref); 173fa9e4066Sahrens rc->rc_removed_count--; 174fa9e4066Sahrens } 175fa9e4066Sahrens } else { 176fa9e4066Sahrens kmem_cache_free(reference_cache, ref); 177fa9e4066Sahrens } 178fa9e4066Sahrens rc->rc_count -= number; 179fa9e4066Sahrens count = rc->rc_count; 180fa9e4066Sahrens mutex_exit(&rc->rc_mtx); 181fa9e4066Sahrens return (count); 182fa9e4066Sahrens } 183fa9e4066Sahrens } 184fa9e4066Sahrens panic("No such hold %p on refcount %llx", holder, 185fa9e4066Sahrens (u_longlong_t)(uintptr_t)rc); 186fa9e4066Sahrens return (-1); 187fa9e4066Sahrens } 188fa9e4066Sahrens 189fa9e4066Sahrens int64_t 190fa9e4066Sahrens refcount_remove(refcount_t *rc, void *holder) 191fa9e4066Sahrens { 192fa9e4066Sahrens return (refcount_remove_many(rc, 1, holder)); 193fa9e4066Sahrens } 194fa9e4066Sahrens 195fa9e4066Sahrens #endif 196