1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 5*4787Sahrens * Common Development and Distribution License (the "License"). 6*4787Sahrens * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 21789Sahrens /* 22*4787Sahrens * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23789Sahrens * Use is subject to license terms. 24789Sahrens */ 25789Sahrens 26789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27789Sahrens 28789Sahrens #include <sys/zfs_context.h> 29789Sahrens #include <sys/refcount.h> 30789Sahrens 31789Sahrens #if defined(DEBUG) || !defined(_KERNEL) 32789Sahrens 33789Sahrens #ifdef _KERNEL 34789Sahrens int reference_tracking_enable = FALSE; /* runs out of memory too easily */ 35789Sahrens #else 36789Sahrens int reference_tracking_enable = TRUE; 37789Sahrens #endif 38789Sahrens int reference_history = 4; /* tunable */ 39789Sahrens 40789Sahrens static kmem_cache_t *reference_cache; 41789Sahrens static kmem_cache_t *reference_history_cache; 42789Sahrens 43789Sahrens void 44789Sahrens refcount_init(void) 45789Sahrens { 46789Sahrens reference_cache = kmem_cache_create("reference_cache", 47789Sahrens sizeof (reference_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 48789Sahrens 49789Sahrens reference_history_cache = kmem_cache_create("reference_history_cache", 50789Sahrens sizeof (uint64_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 51789Sahrens } 52789Sahrens 53789Sahrens void 54789Sahrens refcount_fini(void) 55789Sahrens { 56789Sahrens kmem_cache_destroy(reference_cache); 57789Sahrens kmem_cache_destroy(reference_history_cache); 58789Sahrens } 59789Sahrens 60789Sahrens void 61789Sahrens refcount_create(refcount_t *rc) 62789Sahrens { 63*4787Sahrens mutex_init(&rc->rc_mtx, NULL, MUTEX_DEFAULT, NULL); 64789Sahrens list_create(&rc->rc_list, sizeof (reference_t), 65789Sahrens offsetof(reference_t, ref_link)); 66789Sahrens list_create(&rc->rc_removed, sizeof (reference_t), 67789Sahrens offsetof(reference_t, ref_link)); 68*4787Sahrens rc->rc_count = 0; 69*4787Sahrens rc->rc_removed_count = 0; 70789Sahrens } 71789Sahrens 72789Sahrens void 73789Sahrens refcount_destroy_many(refcount_t *rc, uint64_t number) 74789Sahrens { 75789Sahrens reference_t *ref; 76789Sahrens 77789Sahrens ASSERT(rc->rc_count == number); 78789Sahrens while (ref = list_head(&rc->rc_list)) { 79789Sahrens list_remove(&rc->rc_list, ref); 80789Sahrens kmem_cache_free(reference_cache, ref); 81789Sahrens } 82789Sahrens list_destroy(&rc->rc_list); 83789Sahrens 84789Sahrens while (ref = list_head(&rc->rc_removed)) { 85789Sahrens list_remove(&rc->rc_removed, ref); 86789Sahrens kmem_cache_free(reference_history_cache, ref->ref_removed); 87789Sahrens kmem_cache_free(reference_cache, ref); 88789Sahrens } 89789Sahrens list_destroy(&rc->rc_removed); 90789Sahrens mutex_destroy(&rc->rc_mtx); 91789Sahrens } 92789Sahrens 93789Sahrens void 94789Sahrens refcount_destroy(refcount_t *rc) 95789Sahrens { 96789Sahrens refcount_destroy_many(rc, 0); 97789Sahrens } 98789Sahrens 99789Sahrens int 100789Sahrens refcount_is_zero(refcount_t *rc) 101789Sahrens { 102789Sahrens ASSERT(rc->rc_count >= 0); 103789Sahrens return (rc->rc_count == 0); 104789Sahrens } 105789Sahrens 106789Sahrens int64_t 107789Sahrens refcount_count(refcount_t *rc) 108789Sahrens { 109789Sahrens ASSERT(rc->rc_count >= 0); 110789Sahrens return (rc->rc_count); 111789Sahrens } 112789Sahrens 113789Sahrens int64_t 114789Sahrens refcount_add_many(refcount_t *rc, uint64_t number, void *holder) 115789Sahrens { 116789Sahrens reference_t *ref; 117789Sahrens int64_t count; 118789Sahrens 119789Sahrens if (reference_tracking_enable) { 120789Sahrens ref = kmem_cache_alloc(reference_cache, KM_SLEEP); 121789Sahrens ref->ref_holder = holder; 122789Sahrens ref->ref_number = number; 123789Sahrens } 124789Sahrens mutex_enter(&rc->rc_mtx); 125789Sahrens ASSERT(rc->rc_count >= 0); 126789Sahrens if (reference_tracking_enable) 127789Sahrens list_insert_head(&rc->rc_list, ref); 128789Sahrens rc->rc_count += number; 129789Sahrens count = rc->rc_count; 130789Sahrens mutex_exit(&rc->rc_mtx); 131789Sahrens 132789Sahrens return (count); 133789Sahrens } 134789Sahrens 135789Sahrens int64_t 136789Sahrens refcount_add(refcount_t *rc, void *holder) 137789Sahrens { 138789Sahrens return (refcount_add_many(rc, 1, holder)); 139789Sahrens } 140789Sahrens 141789Sahrens int64_t 142789Sahrens refcount_remove_many(refcount_t *rc, uint64_t number, void *holder) 143789Sahrens { 144789Sahrens reference_t *ref; 145789Sahrens int64_t count; 146789Sahrens 147789Sahrens mutex_enter(&rc->rc_mtx); 148789Sahrens ASSERT(rc->rc_count >= number); 149789Sahrens 150789Sahrens if (!reference_tracking_enable) { 151789Sahrens rc->rc_count -= number; 152789Sahrens count = rc->rc_count; 153789Sahrens mutex_exit(&rc->rc_mtx); 154789Sahrens return (count); 155789Sahrens } 156789Sahrens 157789Sahrens for (ref = list_head(&rc->rc_list); ref; 158789Sahrens ref = list_next(&rc->rc_list, ref)) { 159789Sahrens if (ref->ref_holder == holder && ref->ref_number == number) { 160789Sahrens list_remove(&rc->rc_list, ref); 161789Sahrens if (reference_history > 0) { 162789Sahrens ref->ref_removed = 163789Sahrens kmem_cache_alloc(reference_history_cache, 164789Sahrens KM_SLEEP); 165789Sahrens list_insert_head(&rc->rc_removed, ref); 166789Sahrens rc->rc_removed_count++; 167789Sahrens if (rc->rc_removed_count >= reference_history) { 168789Sahrens ref = list_tail(&rc->rc_removed); 169789Sahrens list_remove(&rc->rc_removed, ref); 170789Sahrens kmem_cache_free(reference_history_cache, 171789Sahrens ref->ref_removed); 172789Sahrens kmem_cache_free(reference_cache, ref); 173789Sahrens rc->rc_removed_count--; 174789Sahrens } 175789Sahrens } else { 176789Sahrens kmem_cache_free(reference_cache, ref); 177789Sahrens } 178789Sahrens rc->rc_count -= number; 179789Sahrens count = rc->rc_count; 180789Sahrens mutex_exit(&rc->rc_mtx); 181789Sahrens return (count); 182789Sahrens } 183789Sahrens } 184789Sahrens panic("No such hold %p on refcount %llx", holder, 185789Sahrens (u_longlong_t)(uintptr_t)rc); 186789Sahrens return (-1); 187789Sahrens } 188789Sahrens 189789Sahrens int64_t 190789Sahrens refcount_remove(refcount_t *rc, void *holder) 191789Sahrens { 192789Sahrens return (refcount_remove_many(rc, 1, holder)); 193789Sahrens } 194789Sahrens 195789Sahrens #endif 196