1*eda14cbcSMatt Macy /* 2*eda14cbcSMatt Macy * CDDL HEADER START 3*eda14cbcSMatt Macy * 4*eda14cbcSMatt Macy * The contents of this file are subject to the terms of the 5*eda14cbcSMatt Macy * Common Development and Distribution License (the "License"). 6*eda14cbcSMatt Macy * You may not use this file except in compliance with the License. 7*eda14cbcSMatt Macy * 8*eda14cbcSMatt Macy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*eda14cbcSMatt Macy * or http://www.opensolaris.org/os/licensing. 10*eda14cbcSMatt Macy * See the License for the specific language governing permissions 11*eda14cbcSMatt Macy * and limitations under the License. 12*eda14cbcSMatt Macy * 13*eda14cbcSMatt Macy * When distributing Covered Code, include this CDDL HEADER in each 14*eda14cbcSMatt Macy * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*eda14cbcSMatt Macy * If applicable, add the following below this CDDL HEADER, with the 16*eda14cbcSMatt Macy * fields enclosed by brackets "[]" replaced with your own identifying 17*eda14cbcSMatt Macy * information: Portions Copyright [yyyy] [name of copyright owner] 18*eda14cbcSMatt Macy * 19*eda14cbcSMatt Macy * CDDL HEADER END 20*eda14cbcSMatt Macy */ 21*eda14cbcSMatt Macy /* 22*eda14cbcSMatt Macy * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23*eda14cbcSMatt Macy * Copyright (c) 2012, 2015 by Delphix. All rights reserved. 24*eda14cbcSMatt Macy */ 25*eda14cbcSMatt Macy 26*eda14cbcSMatt Macy #include <sys/zfs_context.h> 27*eda14cbcSMatt Macy #include <sys/zfs_refcount.h> 28*eda14cbcSMatt Macy 29*eda14cbcSMatt Macy /* 30*eda14cbcSMatt Macy * Reference count tracking is disabled by default. It's memory requirements 31*eda14cbcSMatt Macy * are reasonable, however as implemented it consumes a significant amount of 32*eda14cbcSMatt Macy * cpu time. Until its performance is improved it should be manually enabled. 33*eda14cbcSMatt Macy */ 34*eda14cbcSMatt Macy int reference_tracking_enable = FALSE; 35*eda14cbcSMatt Macy int reference_history = 3; /* tunable */ 36*eda14cbcSMatt Macy 37*eda14cbcSMatt Macy #ifdef ZFS_DEBUG 38*eda14cbcSMatt Macy static kmem_cache_t *reference_cache; 39*eda14cbcSMatt Macy static kmem_cache_t *reference_history_cache; 40*eda14cbcSMatt Macy 41*eda14cbcSMatt Macy void 42*eda14cbcSMatt Macy zfs_refcount_init(void) 43*eda14cbcSMatt Macy { 44*eda14cbcSMatt Macy reference_cache = kmem_cache_create("reference_cache", 45*eda14cbcSMatt Macy sizeof (reference_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 46*eda14cbcSMatt Macy 47*eda14cbcSMatt Macy reference_history_cache = kmem_cache_create("reference_history_cache", 48*eda14cbcSMatt Macy sizeof (uint64_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 49*eda14cbcSMatt Macy } 50*eda14cbcSMatt Macy 51*eda14cbcSMatt Macy void 52*eda14cbcSMatt Macy zfs_refcount_fini(void) 53*eda14cbcSMatt Macy { 54*eda14cbcSMatt Macy kmem_cache_destroy(reference_cache); 55*eda14cbcSMatt Macy kmem_cache_destroy(reference_history_cache); 56*eda14cbcSMatt Macy } 57*eda14cbcSMatt Macy 58*eda14cbcSMatt Macy void 59*eda14cbcSMatt Macy zfs_refcount_create(zfs_refcount_t *rc) 60*eda14cbcSMatt Macy { 61*eda14cbcSMatt Macy mutex_init(&rc->rc_mtx, NULL, MUTEX_DEFAULT, NULL); 62*eda14cbcSMatt Macy list_create(&rc->rc_list, sizeof (reference_t), 63*eda14cbcSMatt Macy offsetof(reference_t, ref_link)); 64*eda14cbcSMatt Macy list_create(&rc->rc_removed, sizeof (reference_t), 65*eda14cbcSMatt Macy offsetof(reference_t, ref_link)); 66*eda14cbcSMatt Macy rc->rc_count = 0; 67*eda14cbcSMatt Macy rc->rc_removed_count = 0; 68*eda14cbcSMatt Macy rc->rc_tracked = reference_tracking_enable; 69*eda14cbcSMatt Macy } 70*eda14cbcSMatt Macy 71*eda14cbcSMatt Macy void 72*eda14cbcSMatt Macy zfs_refcount_create_tracked(zfs_refcount_t *rc) 73*eda14cbcSMatt Macy { 74*eda14cbcSMatt Macy zfs_refcount_create(rc); 75*eda14cbcSMatt Macy rc->rc_tracked = B_TRUE; 76*eda14cbcSMatt Macy } 77*eda14cbcSMatt Macy 78*eda14cbcSMatt Macy void 79*eda14cbcSMatt Macy zfs_refcount_create_untracked(zfs_refcount_t *rc) 80*eda14cbcSMatt Macy { 81*eda14cbcSMatt Macy zfs_refcount_create(rc); 82*eda14cbcSMatt Macy rc->rc_tracked = B_FALSE; 83*eda14cbcSMatt Macy } 84*eda14cbcSMatt Macy 85*eda14cbcSMatt Macy void 86*eda14cbcSMatt Macy zfs_refcount_destroy_many(zfs_refcount_t *rc, uint64_t number) 87*eda14cbcSMatt Macy { 88*eda14cbcSMatt Macy reference_t *ref; 89*eda14cbcSMatt Macy 90*eda14cbcSMatt Macy ASSERT3U(rc->rc_count, ==, number); 91*eda14cbcSMatt Macy while ((ref = list_head(&rc->rc_list))) { 92*eda14cbcSMatt Macy list_remove(&rc->rc_list, ref); 93*eda14cbcSMatt Macy kmem_cache_free(reference_cache, ref); 94*eda14cbcSMatt Macy } 95*eda14cbcSMatt Macy list_destroy(&rc->rc_list); 96*eda14cbcSMatt Macy 97*eda14cbcSMatt Macy while ((ref = list_head(&rc->rc_removed))) { 98*eda14cbcSMatt Macy list_remove(&rc->rc_removed, ref); 99*eda14cbcSMatt Macy kmem_cache_free(reference_history_cache, ref->ref_removed); 100*eda14cbcSMatt Macy kmem_cache_free(reference_cache, ref); 101*eda14cbcSMatt Macy } 102*eda14cbcSMatt Macy list_destroy(&rc->rc_removed); 103*eda14cbcSMatt Macy mutex_destroy(&rc->rc_mtx); 104*eda14cbcSMatt Macy } 105*eda14cbcSMatt Macy 106*eda14cbcSMatt Macy void 107*eda14cbcSMatt Macy zfs_refcount_destroy(zfs_refcount_t *rc) 108*eda14cbcSMatt Macy { 109*eda14cbcSMatt Macy zfs_refcount_destroy_many(rc, 0); 110*eda14cbcSMatt Macy } 111*eda14cbcSMatt Macy 112*eda14cbcSMatt Macy int 113*eda14cbcSMatt Macy zfs_refcount_is_zero(zfs_refcount_t *rc) 114*eda14cbcSMatt Macy { 115*eda14cbcSMatt Macy return (rc->rc_count == 0); 116*eda14cbcSMatt Macy } 117*eda14cbcSMatt Macy 118*eda14cbcSMatt Macy int64_t 119*eda14cbcSMatt Macy zfs_refcount_count(zfs_refcount_t *rc) 120*eda14cbcSMatt Macy { 121*eda14cbcSMatt Macy return (rc->rc_count); 122*eda14cbcSMatt Macy } 123*eda14cbcSMatt Macy 124*eda14cbcSMatt Macy int64_t 125*eda14cbcSMatt Macy zfs_refcount_add_many(zfs_refcount_t *rc, uint64_t number, const void *holder) 126*eda14cbcSMatt Macy { 127*eda14cbcSMatt Macy reference_t *ref = NULL; 128*eda14cbcSMatt Macy int64_t count; 129*eda14cbcSMatt Macy 130*eda14cbcSMatt Macy if (rc->rc_tracked) { 131*eda14cbcSMatt Macy ref = kmem_cache_alloc(reference_cache, KM_SLEEP); 132*eda14cbcSMatt Macy ref->ref_holder = holder; 133*eda14cbcSMatt Macy ref->ref_number = number; 134*eda14cbcSMatt Macy } 135*eda14cbcSMatt Macy mutex_enter(&rc->rc_mtx); 136*eda14cbcSMatt Macy ASSERT3U(rc->rc_count, >=, 0); 137*eda14cbcSMatt Macy if (rc->rc_tracked) 138*eda14cbcSMatt Macy list_insert_head(&rc->rc_list, ref); 139*eda14cbcSMatt Macy rc->rc_count += number; 140*eda14cbcSMatt Macy count = rc->rc_count; 141*eda14cbcSMatt Macy mutex_exit(&rc->rc_mtx); 142*eda14cbcSMatt Macy 143*eda14cbcSMatt Macy return (count); 144*eda14cbcSMatt Macy } 145*eda14cbcSMatt Macy 146*eda14cbcSMatt Macy int64_t 147*eda14cbcSMatt Macy zfs_refcount_add(zfs_refcount_t *rc, const void *holder) 148*eda14cbcSMatt Macy { 149*eda14cbcSMatt Macy return (zfs_refcount_add_many(rc, 1, holder)); 150*eda14cbcSMatt Macy } 151*eda14cbcSMatt Macy 152*eda14cbcSMatt Macy int64_t 153*eda14cbcSMatt Macy zfs_refcount_remove_many(zfs_refcount_t *rc, uint64_t number, 154*eda14cbcSMatt Macy const void *holder) 155*eda14cbcSMatt Macy { 156*eda14cbcSMatt Macy reference_t *ref; 157*eda14cbcSMatt Macy int64_t count; 158*eda14cbcSMatt Macy 159*eda14cbcSMatt Macy mutex_enter(&rc->rc_mtx); 160*eda14cbcSMatt Macy ASSERT3U(rc->rc_count, >=, number); 161*eda14cbcSMatt Macy 162*eda14cbcSMatt Macy if (!rc->rc_tracked) { 163*eda14cbcSMatt Macy rc->rc_count -= number; 164*eda14cbcSMatt Macy count = rc->rc_count; 165*eda14cbcSMatt Macy mutex_exit(&rc->rc_mtx); 166*eda14cbcSMatt Macy return (count); 167*eda14cbcSMatt Macy } 168*eda14cbcSMatt Macy 169*eda14cbcSMatt Macy for (ref = list_head(&rc->rc_list); ref; 170*eda14cbcSMatt Macy ref = list_next(&rc->rc_list, ref)) { 171*eda14cbcSMatt Macy if (ref->ref_holder == holder && ref->ref_number == number) { 172*eda14cbcSMatt Macy list_remove(&rc->rc_list, ref); 173*eda14cbcSMatt Macy if (reference_history > 0) { 174*eda14cbcSMatt Macy ref->ref_removed = 175*eda14cbcSMatt Macy kmem_cache_alloc(reference_history_cache, 176*eda14cbcSMatt Macy KM_SLEEP); 177*eda14cbcSMatt Macy list_insert_head(&rc->rc_removed, ref); 178*eda14cbcSMatt Macy rc->rc_removed_count++; 179*eda14cbcSMatt Macy if (rc->rc_removed_count > reference_history) { 180*eda14cbcSMatt Macy ref = list_tail(&rc->rc_removed); 181*eda14cbcSMatt Macy list_remove(&rc->rc_removed, ref); 182*eda14cbcSMatt Macy kmem_cache_free(reference_history_cache, 183*eda14cbcSMatt Macy ref->ref_removed); 184*eda14cbcSMatt Macy kmem_cache_free(reference_cache, ref); 185*eda14cbcSMatt Macy rc->rc_removed_count--; 186*eda14cbcSMatt Macy } 187*eda14cbcSMatt Macy } else { 188*eda14cbcSMatt Macy kmem_cache_free(reference_cache, ref); 189*eda14cbcSMatt Macy } 190*eda14cbcSMatt Macy rc->rc_count -= number; 191*eda14cbcSMatt Macy count = rc->rc_count; 192*eda14cbcSMatt Macy mutex_exit(&rc->rc_mtx); 193*eda14cbcSMatt Macy return (count); 194*eda14cbcSMatt Macy } 195*eda14cbcSMatt Macy } 196*eda14cbcSMatt Macy panic("No such hold %p on refcount %llx", holder, 197*eda14cbcSMatt Macy (u_longlong_t)(uintptr_t)rc); 198*eda14cbcSMatt Macy return (-1); 199*eda14cbcSMatt Macy } 200*eda14cbcSMatt Macy 201*eda14cbcSMatt Macy int64_t 202*eda14cbcSMatt Macy zfs_refcount_remove(zfs_refcount_t *rc, const void *holder) 203*eda14cbcSMatt Macy { 204*eda14cbcSMatt Macy return (zfs_refcount_remove_many(rc, 1, holder)); 205*eda14cbcSMatt Macy } 206*eda14cbcSMatt Macy 207*eda14cbcSMatt Macy void 208*eda14cbcSMatt Macy zfs_refcount_transfer(zfs_refcount_t *dst, zfs_refcount_t *src) 209*eda14cbcSMatt Macy { 210*eda14cbcSMatt Macy int64_t count, removed_count; 211*eda14cbcSMatt Macy list_t list, removed; 212*eda14cbcSMatt Macy 213*eda14cbcSMatt Macy list_create(&list, sizeof (reference_t), 214*eda14cbcSMatt Macy offsetof(reference_t, ref_link)); 215*eda14cbcSMatt Macy list_create(&removed, sizeof (reference_t), 216*eda14cbcSMatt Macy offsetof(reference_t, ref_link)); 217*eda14cbcSMatt Macy 218*eda14cbcSMatt Macy mutex_enter(&src->rc_mtx); 219*eda14cbcSMatt Macy count = src->rc_count; 220*eda14cbcSMatt Macy removed_count = src->rc_removed_count; 221*eda14cbcSMatt Macy src->rc_count = 0; 222*eda14cbcSMatt Macy src->rc_removed_count = 0; 223*eda14cbcSMatt Macy list_move_tail(&list, &src->rc_list); 224*eda14cbcSMatt Macy list_move_tail(&removed, &src->rc_removed); 225*eda14cbcSMatt Macy mutex_exit(&src->rc_mtx); 226*eda14cbcSMatt Macy 227*eda14cbcSMatt Macy mutex_enter(&dst->rc_mtx); 228*eda14cbcSMatt Macy dst->rc_count += count; 229*eda14cbcSMatt Macy dst->rc_removed_count += removed_count; 230*eda14cbcSMatt Macy list_move_tail(&dst->rc_list, &list); 231*eda14cbcSMatt Macy list_move_tail(&dst->rc_removed, &removed); 232*eda14cbcSMatt Macy mutex_exit(&dst->rc_mtx); 233*eda14cbcSMatt Macy 234*eda14cbcSMatt Macy list_destroy(&list); 235*eda14cbcSMatt Macy list_destroy(&removed); 236*eda14cbcSMatt Macy } 237*eda14cbcSMatt Macy 238*eda14cbcSMatt Macy void 239*eda14cbcSMatt Macy zfs_refcount_transfer_ownership_many(zfs_refcount_t *rc, uint64_t number, 240*eda14cbcSMatt Macy const void *current_holder, const void *new_holder) 241*eda14cbcSMatt Macy { 242*eda14cbcSMatt Macy reference_t *ref; 243*eda14cbcSMatt Macy boolean_t found = B_FALSE; 244*eda14cbcSMatt Macy 245*eda14cbcSMatt Macy mutex_enter(&rc->rc_mtx); 246*eda14cbcSMatt Macy if (!rc->rc_tracked) { 247*eda14cbcSMatt Macy mutex_exit(&rc->rc_mtx); 248*eda14cbcSMatt Macy return; 249*eda14cbcSMatt Macy } 250*eda14cbcSMatt Macy 251*eda14cbcSMatt Macy for (ref = list_head(&rc->rc_list); ref; 252*eda14cbcSMatt Macy ref = list_next(&rc->rc_list, ref)) { 253*eda14cbcSMatt Macy if (ref->ref_holder == current_holder && 254*eda14cbcSMatt Macy ref->ref_number == number) { 255*eda14cbcSMatt Macy ref->ref_holder = new_holder; 256*eda14cbcSMatt Macy found = B_TRUE; 257*eda14cbcSMatt Macy break; 258*eda14cbcSMatt Macy } 259*eda14cbcSMatt Macy } 260*eda14cbcSMatt Macy ASSERT(found); 261*eda14cbcSMatt Macy mutex_exit(&rc->rc_mtx); 262*eda14cbcSMatt Macy } 263*eda14cbcSMatt Macy 264*eda14cbcSMatt Macy void 265*eda14cbcSMatt Macy zfs_refcount_transfer_ownership(zfs_refcount_t *rc, const void *current_holder, 266*eda14cbcSMatt Macy const void *new_holder) 267*eda14cbcSMatt Macy { 268*eda14cbcSMatt Macy return (zfs_refcount_transfer_ownership_many(rc, 1, current_holder, 269*eda14cbcSMatt Macy new_holder)); 270*eda14cbcSMatt Macy } 271*eda14cbcSMatt Macy 272*eda14cbcSMatt Macy /* 273*eda14cbcSMatt Macy * If tracking is enabled, return true if a reference exists that matches 274*eda14cbcSMatt Macy * the "holder" tag. If tracking is disabled, then return true if a reference 275*eda14cbcSMatt Macy * might be held. 276*eda14cbcSMatt Macy */ 277*eda14cbcSMatt Macy boolean_t 278*eda14cbcSMatt Macy zfs_refcount_held(zfs_refcount_t *rc, const void *holder) 279*eda14cbcSMatt Macy { 280*eda14cbcSMatt Macy reference_t *ref; 281*eda14cbcSMatt Macy 282*eda14cbcSMatt Macy mutex_enter(&rc->rc_mtx); 283*eda14cbcSMatt Macy 284*eda14cbcSMatt Macy if (!rc->rc_tracked) { 285*eda14cbcSMatt Macy mutex_exit(&rc->rc_mtx); 286*eda14cbcSMatt Macy return (rc->rc_count > 0); 287*eda14cbcSMatt Macy } 288*eda14cbcSMatt Macy 289*eda14cbcSMatt Macy for (ref = list_head(&rc->rc_list); ref; 290*eda14cbcSMatt Macy ref = list_next(&rc->rc_list, ref)) { 291*eda14cbcSMatt Macy if (ref->ref_holder == holder) { 292*eda14cbcSMatt Macy mutex_exit(&rc->rc_mtx); 293*eda14cbcSMatt Macy return (B_TRUE); 294*eda14cbcSMatt Macy } 295*eda14cbcSMatt Macy } 296*eda14cbcSMatt Macy mutex_exit(&rc->rc_mtx); 297*eda14cbcSMatt Macy return (B_FALSE); 298*eda14cbcSMatt Macy } 299*eda14cbcSMatt Macy 300*eda14cbcSMatt Macy /* 301*eda14cbcSMatt Macy * If tracking is enabled, return true if a reference does not exist that 302*eda14cbcSMatt Macy * matches the "holder" tag. If tracking is disabled, always return true 303*eda14cbcSMatt Macy * since the reference might not be held. 304*eda14cbcSMatt Macy */ 305*eda14cbcSMatt Macy boolean_t 306*eda14cbcSMatt Macy zfs_refcount_not_held(zfs_refcount_t *rc, const void *holder) 307*eda14cbcSMatt Macy { 308*eda14cbcSMatt Macy reference_t *ref; 309*eda14cbcSMatt Macy 310*eda14cbcSMatt Macy mutex_enter(&rc->rc_mtx); 311*eda14cbcSMatt Macy 312*eda14cbcSMatt Macy if (!rc->rc_tracked) { 313*eda14cbcSMatt Macy mutex_exit(&rc->rc_mtx); 314*eda14cbcSMatt Macy return (B_TRUE); 315*eda14cbcSMatt Macy } 316*eda14cbcSMatt Macy 317*eda14cbcSMatt Macy for (ref = list_head(&rc->rc_list); ref; 318*eda14cbcSMatt Macy ref = list_next(&rc->rc_list, ref)) { 319*eda14cbcSMatt Macy if (ref->ref_holder == holder) { 320*eda14cbcSMatt Macy mutex_exit(&rc->rc_mtx); 321*eda14cbcSMatt Macy return (B_FALSE); 322*eda14cbcSMatt Macy } 323*eda14cbcSMatt Macy } 324*eda14cbcSMatt Macy mutex_exit(&rc->rc_mtx); 325*eda14cbcSMatt Macy return (B_TRUE); 326*eda14cbcSMatt Macy } 327*eda14cbcSMatt Macy #endif /* ZFS_DEBUG */ 328