1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 591ebeef5Sahrens * Common Development and Distribution License (the "License"). 691ebeef5Sahrens * 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 /* 223f9d6ad7SLin Ling * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23fa9e4066Sahrens */ 24fa9e4066Sahrens 25fa9e4066Sahrens #include <sys/zfs_context.h> 26fa9e4066Sahrens #include <sys/refcount.h> 27fa9e4066Sahrens 28*744947dcSTom Erickson #ifdef ZFS_DEBUG 29fa9e4066Sahrens 30fa9e4066Sahrens #ifdef _KERNEL 31fa9e4066Sahrens int reference_tracking_enable = FALSE; /* runs out of memory too easily */ 32fa9e4066Sahrens #else 33fa9e4066Sahrens int reference_tracking_enable = TRUE; 34fa9e4066Sahrens #endif 35fa9e4066Sahrens int reference_history = 4; /* tunable */ 36fa9e4066Sahrens 37fa9e4066Sahrens static kmem_cache_t *reference_cache; 38fa9e4066Sahrens static kmem_cache_t *reference_history_cache; 39fa9e4066Sahrens 40fa9e4066Sahrens void 41fa9e4066Sahrens refcount_init(void) 42fa9e4066Sahrens { 43fa9e4066Sahrens reference_cache = kmem_cache_create("reference_cache", 44fa9e4066Sahrens sizeof (reference_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 45fa9e4066Sahrens 46fa9e4066Sahrens reference_history_cache = kmem_cache_create("reference_history_cache", 47fa9e4066Sahrens sizeof (uint64_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 48fa9e4066Sahrens } 49fa9e4066Sahrens 50fa9e4066Sahrens void 51fa9e4066Sahrens refcount_fini(void) 52fa9e4066Sahrens { 53fa9e4066Sahrens kmem_cache_destroy(reference_cache); 54fa9e4066Sahrens kmem_cache_destroy(reference_history_cache); 55fa9e4066Sahrens } 56fa9e4066Sahrens 57fa9e4066Sahrens void 58fa9e4066Sahrens refcount_create(refcount_t *rc) 59fa9e4066Sahrens { 6091ebeef5Sahrens mutex_init(&rc->rc_mtx, NULL, MUTEX_DEFAULT, NULL); 61fa9e4066Sahrens list_create(&rc->rc_list, sizeof (reference_t), 62fa9e4066Sahrens offsetof(reference_t, ref_link)); 63fa9e4066Sahrens list_create(&rc->rc_removed, sizeof (reference_t), 64fa9e4066Sahrens offsetof(reference_t, ref_link)); 6591ebeef5Sahrens rc->rc_count = 0; 6691ebeef5Sahrens rc->rc_removed_count = 0; 67fa9e4066Sahrens } 68fa9e4066Sahrens 69fa9e4066Sahrens void 70fa9e4066Sahrens refcount_destroy_many(refcount_t *rc, uint64_t number) 71fa9e4066Sahrens { 72fa9e4066Sahrens reference_t *ref; 73fa9e4066Sahrens 74fa9e4066Sahrens ASSERT(rc->rc_count == number); 75fa9e4066Sahrens while (ref = list_head(&rc->rc_list)) { 76fa9e4066Sahrens list_remove(&rc->rc_list, ref); 77fa9e4066Sahrens kmem_cache_free(reference_cache, ref); 78fa9e4066Sahrens } 79fa9e4066Sahrens list_destroy(&rc->rc_list); 80fa9e4066Sahrens 81fa9e4066Sahrens while (ref = list_head(&rc->rc_removed)) { 82fa9e4066Sahrens list_remove(&rc->rc_removed, ref); 83fa9e4066Sahrens kmem_cache_free(reference_history_cache, ref->ref_removed); 84fa9e4066Sahrens kmem_cache_free(reference_cache, ref); 85fa9e4066Sahrens } 86fa9e4066Sahrens list_destroy(&rc->rc_removed); 87fa9e4066Sahrens mutex_destroy(&rc->rc_mtx); 88fa9e4066Sahrens } 89fa9e4066Sahrens 90fa9e4066Sahrens void 91fa9e4066Sahrens refcount_destroy(refcount_t *rc) 92fa9e4066Sahrens { 93fa9e4066Sahrens refcount_destroy_many(rc, 0); 94fa9e4066Sahrens } 95fa9e4066Sahrens 96fa9e4066Sahrens int 97fa9e4066Sahrens refcount_is_zero(refcount_t *rc) 98fa9e4066Sahrens { 99fa9e4066Sahrens ASSERT(rc->rc_count >= 0); 100fa9e4066Sahrens return (rc->rc_count == 0); 101fa9e4066Sahrens } 102fa9e4066Sahrens 103fa9e4066Sahrens int64_t 104fa9e4066Sahrens refcount_count(refcount_t *rc) 105fa9e4066Sahrens { 106fa9e4066Sahrens ASSERT(rc->rc_count >= 0); 107fa9e4066Sahrens return (rc->rc_count); 108fa9e4066Sahrens } 109fa9e4066Sahrens 110fa9e4066Sahrens int64_t 111fa9e4066Sahrens refcount_add_many(refcount_t *rc, uint64_t number, void *holder) 112fa9e4066Sahrens { 113fa9e4066Sahrens reference_t *ref; 114fa9e4066Sahrens int64_t count; 115fa9e4066Sahrens 116fa9e4066Sahrens if (reference_tracking_enable) { 117fa9e4066Sahrens ref = kmem_cache_alloc(reference_cache, KM_SLEEP); 118fa9e4066Sahrens ref->ref_holder = holder; 119fa9e4066Sahrens ref->ref_number = number; 120fa9e4066Sahrens } 121fa9e4066Sahrens mutex_enter(&rc->rc_mtx); 122fa9e4066Sahrens ASSERT(rc->rc_count >= 0); 123fa9e4066Sahrens if (reference_tracking_enable) 124fa9e4066Sahrens list_insert_head(&rc->rc_list, ref); 125fa9e4066Sahrens rc->rc_count += number; 126fa9e4066Sahrens count = rc->rc_count; 127fa9e4066Sahrens mutex_exit(&rc->rc_mtx); 128fa9e4066Sahrens 129fa9e4066Sahrens return (count); 130fa9e4066Sahrens } 131fa9e4066Sahrens 132fa9e4066Sahrens int64_t 133fa9e4066Sahrens refcount_add(refcount_t *rc, void *holder) 134fa9e4066Sahrens { 135fa9e4066Sahrens return (refcount_add_many(rc, 1, holder)); 136fa9e4066Sahrens } 137fa9e4066Sahrens 138fa9e4066Sahrens int64_t 139fa9e4066Sahrens refcount_remove_many(refcount_t *rc, uint64_t number, void *holder) 140fa9e4066Sahrens { 141fa9e4066Sahrens reference_t *ref; 142fa9e4066Sahrens int64_t count; 143fa9e4066Sahrens 144fa9e4066Sahrens mutex_enter(&rc->rc_mtx); 145fa9e4066Sahrens ASSERT(rc->rc_count >= number); 146fa9e4066Sahrens 147fa9e4066Sahrens if (!reference_tracking_enable) { 148fa9e4066Sahrens rc->rc_count -= number; 149fa9e4066Sahrens count = rc->rc_count; 150fa9e4066Sahrens mutex_exit(&rc->rc_mtx); 151fa9e4066Sahrens return (count); 152fa9e4066Sahrens } 153fa9e4066Sahrens 154fa9e4066Sahrens for (ref = list_head(&rc->rc_list); ref; 155fa9e4066Sahrens ref = list_next(&rc->rc_list, ref)) { 156fa9e4066Sahrens if (ref->ref_holder == holder && ref->ref_number == number) { 157fa9e4066Sahrens list_remove(&rc->rc_list, ref); 158fa9e4066Sahrens if (reference_history > 0) { 159fa9e4066Sahrens ref->ref_removed = 160fa9e4066Sahrens kmem_cache_alloc(reference_history_cache, 161fa9e4066Sahrens KM_SLEEP); 162fa9e4066Sahrens list_insert_head(&rc->rc_removed, ref); 163fa9e4066Sahrens rc->rc_removed_count++; 164fa9e4066Sahrens if (rc->rc_removed_count >= reference_history) { 165fa9e4066Sahrens ref = list_tail(&rc->rc_removed); 166fa9e4066Sahrens list_remove(&rc->rc_removed, ref); 167fa9e4066Sahrens kmem_cache_free(reference_history_cache, 168fa9e4066Sahrens ref->ref_removed); 169fa9e4066Sahrens kmem_cache_free(reference_cache, ref); 170fa9e4066Sahrens rc->rc_removed_count--; 171fa9e4066Sahrens } 172fa9e4066Sahrens } else { 173fa9e4066Sahrens kmem_cache_free(reference_cache, ref); 174fa9e4066Sahrens } 175fa9e4066Sahrens rc->rc_count -= number; 176fa9e4066Sahrens count = rc->rc_count; 177fa9e4066Sahrens mutex_exit(&rc->rc_mtx); 178fa9e4066Sahrens return (count); 179fa9e4066Sahrens } 180fa9e4066Sahrens } 181fa9e4066Sahrens panic("No such hold %p on refcount %llx", holder, 182fa9e4066Sahrens (u_longlong_t)(uintptr_t)rc); 183fa9e4066Sahrens return (-1); 184fa9e4066Sahrens } 185fa9e4066Sahrens 186fa9e4066Sahrens int64_t 187fa9e4066Sahrens refcount_remove(refcount_t *rc, void *holder) 188fa9e4066Sahrens { 189fa9e4066Sahrens return (refcount_remove_many(rc, 1, holder)); 190fa9e4066Sahrens } 191fa9e4066Sahrens 192*744947dcSTom Erickson void 193*744947dcSTom Erickson refcount_transfer(refcount_t *dst, refcount_t *src) 194*744947dcSTom Erickson { 195*744947dcSTom Erickson int64_t count, removed_count; 196*744947dcSTom Erickson list_t list, removed; 197*744947dcSTom Erickson 198*744947dcSTom Erickson list_create(&list, sizeof (reference_t), 199*744947dcSTom Erickson offsetof(reference_t, ref_link)); 200*744947dcSTom Erickson list_create(&removed, sizeof (reference_t), 201*744947dcSTom Erickson offsetof(reference_t, ref_link)); 202*744947dcSTom Erickson 203*744947dcSTom Erickson mutex_enter(&src->rc_mtx); 204*744947dcSTom Erickson count = src->rc_count; 205*744947dcSTom Erickson removed_count = src->rc_removed_count; 206*744947dcSTom Erickson src->rc_count = 0; 207*744947dcSTom Erickson src->rc_removed_count = 0; 208*744947dcSTom Erickson list_move_tail(&list, &src->rc_list); 209*744947dcSTom Erickson list_move_tail(&removed, &src->rc_removed); 210*744947dcSTom Erickson mutex_exit(&src->rc_mtx); 211*744947dcSTom Erickson 212*744947dcSTom Erickson mutex_enter(&dst->rc_mtx); 213*744947dcSTom Erickson dst->rc_count += count; 214*744947dcSTom Erickson dst->rc_removed_count += removed_count; 215*744947dcSTom Erickson list_move_tail(&dst->rc_list, &list); 216*744947dcSTom Erickson list_move_tail(&dst->rc_removed, &removed); 217*744947dcSTom Erickson mutex_exit(&dst->rc_mtx); 218*744947dcSTom Erickson 219*744947dcSTom Erickson list_destroy(&list); 220*744947dcSTom Erickson list_destroy(&removed); 221*744947dcSTom Erickson } 222*744947dcSTom Erickson 223*744947dcSTom Erickson #endif /* ZFS_DEBUG */ 224