FreeBSD ZFS
The Zettabyte File System

refcount.c

Go to the documentation of this file.
00001 /*
00002  * CDDL HEADER START
00003  *
00004  * The contents of this file are subject to the terms of the
00005  * Common Development and Distribution License (the "License").
00006  * You may not use this file except in compliance with the License.
00007  *
00008  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
00009  * or http://www.opensolaris.org/os/licensing.
00010  * See the License for the specific language governing permissions
00011  * and limitations under the License.
00012  *
00013  * When distributing Covered Code, include this CDDL HEADER in each
00014  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
00015  * If applicable, add the following below this CDDL HEADER, with the
00016  * fields enclosed by brackets "[]" replaced with your own identifying
00017  * information: Portions Copyright [yyyy] [name of copyright owner]
00018  *
00019  * CDDL HEADER END
00020  */
00021 /*
00022  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
00023  */
00024 
00025 #include <sys/zfs_context.h>
00026 #include <sys/refcount.h>
00027 
00028 #ifdef  ZFS_DEBUG
00029 
00030 #ifdef _KERNEL
00031 int reference_tracking_enable = FALSE; /* runs out of memory too easily */
00032 #else
00033 int reference_tracking_enable = TRUE;
00034 #endif
00035 int reference_history = 4; /* tunable */
00036 
00037 static kmem_cache_t *reference_cache;
00038 static kmem_cache_t *reference_history_cache;
00039 
00040 void
00041 refcount_sysinit(void)
00042 {
00043         reference_cache = kmem_cache_create("reference_cache",
00044             sizeof (reference_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
00045 
00046         reference_history_cache = kmem_cache_create("reference_history_cache",
00047             sizeof (uint64_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
00048 }
00049 
00050 void
00051 refcount_fini(void)
00052 {
00053         kmem_cache_destroy(reference_cache);
00054         kmem_cache_destroy(reference_history_cache);
00055 }
00056 
00058 void
00059 refcount_create(refcount_t *rc)
00060 {
00061         mutex_init(&rc->rc_mtx, NULL, MUTEX_DEFAULT, NULL);
00062         list_create(&rc->rc_list, sizeof (reference_t),
00063             offsetof(reference_t, ref_link));
00064         list_create(&rc->rc_removed, sizeof (reference_t),
00065             offsetof(reference_t, ref_link));
00066         rc->rc_count = 0;
00067         rc->rc_removed_count = 0;
00068 }
00069 
00070 void
00071 refcount_destroy_many(refcount_t *rc, uint64_t number)
00072 {
00073         reference_t *ref;
00074 
00075         ASSERT(rc->rc_count == number);
00076         while (ref = list_head(&rc->rc_list)) {
00077                 list_remove(&rc->rc_list, ref);
00078                 kmem_cache_free(reference_cache, ref);
00079         }
00080         list_destroy(&rc->rc_list);
00081 
00082         while (ref = list_head(&rc->rc_removed)) {
00083                 list_remove(&rc->rc_removed, ref);
00084                 kmem_cache_free(reference_history_cache, ref->ref_removed);
00085                 kmem_cache_free(reference_cache, ref);
00086         }
00087         list_destroy(&rc->rc_removed);
00088         mutex_destroy(&rc->rc_mtx);
00089 }
00090 
00091 void
00092 refcount_destroy(refcount_t *rc)
00093 {
00094         refcount_destroy_many(rc, 0);
00095 }
00096 
00097 int
00098 refcount_is_zero(refcount_t *rc)
00099 {
00100         ASSERT(rc->rc_count >= 0);
00101         return (rc->rc_count == 0);
00102 }
00103 
00104 int64_t
00105 refcount_count(refcount_t *rc)
00106 {
00107         ASSERT(rc->rc_count >= 0);
00108         return (rc->rc_count);
00109 }
00110 
00111 int64_t
00112 refcount_add_many(refcount_t *rc, uint64_t number, void *holder)
00113 {
00114         reference_t *ref;
00115         int64_t count;
00116 
00117         if (reference_tracking_enable) {
00118                 ref = kmem_cache_alloc(reference_cache, KM_SLEEP);
00119                 ref->ref_holder = holder;
00120                 ref->ref_number = number;
00121         }
00122         mutex_enter(&rc->rc_mtx);
00123         ASSERT(rc->rc_count >= 0);
00124         if (reference_tracking_enable)
00125                 list_insert_head(&rc->rc_list, ref);
00126         rc->rc_count += number;
00127         count = rc->rc_count;
00128         mutex_exit(&rc->rc_mtx);
00129 
00130         return (count);
00131 }
00132 
00133 int64_t
00134 refcount_add(refcount_t *rc, void *holder)
00135 {
00136         return (refcount_add_many(rc, 1, holder));
00137 }
00138 
00139 int64_t
00140 refcount_remove_many(refcount_t *rc, uint64_t number, void *holder)
00141 {
00142         reference_t *ref;
00143         int64_t count;
00144 
00145         mutex_enter(&rc->rc_mtx);
00146         ASSERT(rc->rc_count >= number);
00147 
00148         if (!reference_tracking_enable) {
00149                 rc->rc_count -= number;
00150                 count = rc->rc_count;
00151                 mutex_exit(&rc->rc_mtx);
00152                 return (count);
00153         }
00154 
00155         for (ref = list_head(&rc->rc_list); ref;
00156             ref = list_next(&rc->rc_list, ref)) {
00157                 if (ref->ref_holder == holder && ref->ref_number == number) {
00158                         list_remove(&rc->rc_list, ref);
00159                         if (reference_history > 0) {
00160                                 ref->ref_removed =
00161                                     kmem_cache_alloc(reference_history_cache,
00162                                     KM_SLEEP);
00163                                 list_insert_head(&rc->rc_removed, ref);
00164                                 rc->rc_removed_count++;
00165                                 if (rc->rc_removed_count >= reference_history) {
00166                                         ref = list_tail(&rc->rc_removed);
00167                                         list_remove(&rc->rc_removed, ref);
00168                                         kmem_cache_free(reference_history_cache,
00169                                             ref->ref_removed);
00170                                         kmem_cache_free(reference_cache, ref);
00171                                         rc->rc_removed_count--;
00172                                 }
00173                         } else {
00174                                 kmem_cache_free(reference_cache, ref);
00175                         }
00176                         rc->rc_count -= number;
00177                         count = rc->rc_count;
00178                         mutex_exit(&rc->rc_mtx);
00179                         return (count);
00180                 }
00181         }
00182         panic("No such hold %p on refcount %llx", holder,
00183             (u_longlong_t)(uintptr_t)rc);
00184         return (-1);
00185 }
00186 
00187 int64_t
00188 refcount_remove(refcount_t *rc, void *holder)
00189 {
00190         return (refcount_remove_many(rc, 1, holder));
00191 }
00192 
00193 void
00194 refcount_transfer(refcount_t *dst, refcount_t *src)
00195 {
00196         int64_t count, removed_count;
00197         list_t list, removed;
00198 
00199         list_create(&list, sizeof (reference_t),
00200             offsetof(reference_t, ref_link));
00201         list_create(&removed, sizeof (reference_t),
00202             offsetof(reference_t, ref_link));
00203 
00204         mutex_enter(&src->rc_mtx);
00205         count = src->rc_count;
00206         removed_count = src->rc_removed_count;
00207         src->rc_count = 0;
00208         src->rc_removed_count = 0;
00209         list_move_tail(&list, &src->rc_list);
00210         list_move_tail(&removed, &src->rc_removed);
00211         mutex_exit(&src->rc_mtx);
00212 
00213         mutex_enter(&dst->rc_mtx);
00214         dst->rc_count += count;
00215         dst->rc_removed_count += removed_count;
00216         list_move_tail(&dst->rc_list, &list);
00217         list_move_tail(&dst->rc_removed, &removed);
00218         mutex_exit(&dst->rc_mtx);
00219 
00220         list_destroy(&list);
00221         list_destroy(&removed);
00222 }
00223 
00224 #endif  /* ZFS_DEBUG */
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines