1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 54787Sahrens * Common Development and Distribution License (the "License"). 64787Sahrens * 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*12296SLin.Ling@Sun.COM * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23789Sahrens */ 24789Sahrens 25789Sahrens #include <sys/zfs_context.h> 26789Sahrens #include <sys/refcount.h> 27789Sahrens 28789Sahrens #if defined(DEBUG) || !defined(_KERNEL) 29789Sahrens 30789Sahrens #ifdef _KERNEL 31789Sahrens int reference_tracking_enable = FALSE; /* runs out of memory too easily */ 32789Sahrens #else 33789Sahrens int reference_tracking_enable = TRUE; 34789Sahrens #endif 35789Sahrens int reference_history = 4; /* tunable */ 36789Sahrens 37789Sahrens static kmem_cache_t *reference_cache; 38789Sahrens static kmem_cache_t *reference_history_cache; 39789Sahrens 40789Sahrens void 41789Sahrens refcount_init(void) 42789Sahrens { 43789Sahrens reference_cache = kmem_cache_create("reference_cache", 44789Sahrens sizeof (reference_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 45789Sahrens 46789Sahrens reference_history_cache = kmem_cache_create("reference_history_cache", 47789Sahrens sizeof (uint64_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 48789Sahrens } 49789Sahrens 50789Sahrens void 51789Sahrens refcount_fini(void) 52789Sahrens { 53789Sahrens kmem_cache_destroy(reference_cache); 54789Sahrens kmem_cache_destroy(reference_history_cache); 55789Sahrens } 56789Sahrens 57789Sahrens void 58789Sahrens refcount_create(refcount_t *rc) 59789Sahrens { 604787Sahrens mutex_init(&rc->rc_mtx, NULL, MUTEX_DEFAULT, NULL); 61789Sahrens list_create(&rc->rc_list, sizeof (reference_t), 62789Sahrens offsetof(reference_t, ref_link)); 63789Sahrens list_create(&rc->rc_removed, sizeof (reference_t), 64789Sahrens offsetof(reference_t, ref_link)); 654787Sahrens rc->rc_count = 0; 664787Sahrens rc->rc_removed_count = 0; 67789Sahrens } 68789Sahrens 69789Sahrens void 70789Sahrens refcount_destroy_many(refcount_t *rc, uint64_t number) 71789Sahrens { 72789Sahrens reference_t *ref; 73789Sahrens 74789Sahrens ASSERT(rc->rc_count == number); 75789Sahrens while (ref = list_head(&rc->rc_list)) { 76789Sahrens list_remove(&rc->rc_list, ref); 77789Sahrens kmem_cache_free(reference_cache, ref); 78789Sahrens } 79789Sahrens list_destroy(&rc->rc_list); 80789Sahrens 81789Sahrens while (ref = list_head(&rc->rc_removed)) { 82789Sahrens list_remove(&rc->rc_removed, ref); 83789Sahrens kmem_cache_free(reference_history_cache, ref->ref_removed); 84789Sahrens kmem_cache_free(reference_cache, ref); 85789Sahrens } 86789Sahrens list_destroy(&rc->rc_removed); 87789Sahrens mutex_destroy(&rc->rc_mtx); 88789Sahrens } 89789Sahrens 90789Sahrens void 91789Sahrens refcount_destroy(refcount_t *rc) 92789Sahrens { 93789Sahrens refcount_destroy_many(rc, 0); 94789Sahrens } 95789Sahrens 96789Sahrens int 97789Sahrens refcount_is_zero(refcount_t *rc) 98789Sahrens { 99789Sahrens ASSERT(rc->rc_count >= 0); 100789Sahrens return (rc->rc_count == 0); 101789Sahrens } 102789Sahrens 103789Sahrens int64_t 104789Sahrens refcount_count(refcount_t *rc) 105789Sahrens { 106789Sahrens ASSERT(rc->rc_count >= 0); 107789Sahrens return (rc->rc_count); 108789Sahrens } 109789Sahrens 110789Sahrens int64_t 111789Sahrens refcount_add_many(refcount_t *rc, uint64_t number, void *holder) 112789Sahrens { 113789Sahrens reference_t *ref; 114789Sahrens int64_t count; 115789Sahrens 116789Sahrens if (reference_tracking_enable) { 117789Sahrens ref = kmem_cache_alloc(reference_cache, KM_SLEEP); 118789Sahrens ref->ref_holder = holder; 119789Sahrens ref->ref_number = number; 120789Sahrens } 121789Sahrens mutex_enter(&rc->rc_mtx); 122789Sahrens ASSERT(rc->rc_count >= 0); 123789Sahrens if (reference_tracking_enable) 124789Sahrens list_insert_head(&rc->rc_list, ref); 125789Sahrens rc->rc_count += number; 126789Sahrens count = rc->rc_count; 127789Sahrens mutex_exit(&rc->rc_mtx); 128789Sahrens 129789Sahrens return (count); 130789Sahrens } 131789Sahrens 132789Sahrens int64_t 133789Sahrens refcount_add(refcount_t *rc, void *holder) 134789Sahrens { 135789Sahrens return (refcount_add_many(rc, 1, holder)); 136789Sahrens } 137789Sahrens 138789Sahrens int64_t 139789Sahrens refcount_remove_many(refcount_t *rc, uint64_t number, void *holder) 140789Sahrens { 141789Sahrens reference_t *ref; 142789Sahrens int64_t count; 143789Sahrens 144789Sahrens mutex_enter(&rc->rc_mtx); 145789Sahrens ASSERT(rc->rc_count >= number); 146789Sahrens 147789Sahrens if (!reference_tracking_enable) { 148789Sahrens rc->rc_count -= number; 149789Sahrens count = rc->rc_count; 150789Sahrens mutex_exit(&rc->rc_mtx); 151789Sahrens return (count); 152789Sahrens } 153789Sahrens 154789Sahrens for (ref = list_head(&rc->rc_list); ref; 155789Sahrens ref = list_next(&rc->rc_list, ref)) { 156789Sahrens if (ref->ref_holder == holder && ref->ref_number == number) { 157789Sahrens list_remove(&rc->rc_list, ref); 158789Sahrens if (reference_history > 0) { 159789Sahrens ref->ref_removed = 160789Sahrens kmem_cache_alloc(reference_history_cache, 161789Sahrens KM_SLEEP); 162789Sahrens list_insert_head(&rc->rc_removed, ref); 163789Sahrens rc->rc_removed_count++; 164789Sahrens if (rc->rc_removed_count >= reference_history) { 165789Sahrens ref = list_tail(&rc->rc_removed); 166789Sahrens list_remove(&rc->rc_removed, ref); 167789Sahrens kmem_cache_free(reference_history_cache, 168789Sahrens ref->ref_removed); 169789Sahrens kmem_cache_free(reference_cache, ref); 170789Sahrens rc->rc_removed_count--; 171789Sahrens } 172789Sahrens } else { 173789Sahrens kmem_cache_free(reference_cache, ref); 174789Sahrens } 175789Sahrens rc->rc_count -= number; 176789Sahrens count = rc->rc_count; 177789Sahrens mutex_exit(&rc->rc_mtx); 178789Sahrens return (count); 179789Sahrens } 180789Sahrens } 181789Sahrens panic("No such hold %p on refcount %llx", holder, 182789Sahrens (u_longlong_t)(uintptr_t)rc); 183789Sahrens return (-1); 184789Sahrens } 185789Sahrens 186789Sahrens int64_t 187789Sahrens refcount_remove(refcount_t *rc, void *holder) 188789Sahrens { 189789Sahrens return (refcount_remove_many(rc, 1, holder)); 190789Sahrens } 191789Sahrens 192789Sahrens #endif 193