author | Joshua M. Clulow <jmc@joyent.com> |
Mon, 04 Mar 2013 23:52:56 +0000 | |
changeset 14188 | afe390b9f1e0 |
parent 13973 | 4972ab336f54 |
permissions | -rw-r--r-- |
789 | 1 |
/* |
2 |
* CDDL HEADER START |
|
3 |
* |
|
4 |
* The contents of this file are subject to the terms of the |
|
4787 | 5 |
* Common Development and Distribution License (the "License"). |
6 |
* You may not use this file except in compliance with the License. |
|
789 | 7 |
* |
8 |
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
|
9 |
* or http://www.opensolaris.org/os/licensing. |
|
10 |
* See the License for the specific language governing permissions |
|
11 |
* and limitations under the License. |
|
12 |
* |
|
13 |
* When distributing Covered Code, include this CDDL HEADER in each |
|
14 |
* file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
|
15 |
* If applicable, add the following below this CDDL HEADER, with the |
|
16 |
* fields enclosed by brackets "[]" replaced with your own identifying |
|
17 |
* information: Portions Copyright [yyyy] [name of copyright owner] |
|
18 |
* |
|
19 |
* CDDL HEADER END |
|
20 |
*/ |
|
21 |
/* |
|
12296
7cf402a7f374
6675946 'zpool status' should show the progress of resilvering for individual disk.
Lin Ling <Lin.Ling@Sun.COM>
parents:
4787
diff
changeset
|
22 |
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. |
13973
4972ab336f54
3464 zfs synctask code needs restructuring
Matthew Ahrens <mahrens@delphix.com>
parents:
13952
diff
changeset
|
23 |
* Copyright (c) 2012 by Delphix. All rights reserved. |
789 | 24 |
*/ |
25 |
||
26 |
#include <sys/zfs_context.h> |
|
27 |
#include <sys/refcount.h> |
|
28 |
||
12684
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
29 |
#ifdef ZFS_DEBUG |
789 | 30 |
|
31 |
#ifdef _KERNEL |
|
32 |
int reference_tracking_enable = FALSE; /* runs out of memory too easily */ |
|
33 |
#else |
|
34 |
int reference_tracking_enable = TRUE; |
|
35 |
#endif |
|
13973
4972ab336f54
3464 zfs synctask code needs restructuring
Matthew Ahrens <mahrens@delphix.com>
parents:
13952
diff
changeset
|
36 |
int reference_history = 3; /* tunable */ |
789 | 37 |
|
38 |
static kmem_cache_t *reference_cache; |
|
39 |
static kmem_cache_t *reference_history_cache; |
|
40 |
||
41 |
void |
|
42 |
refcount_init(void) |
|
43 |
{ |
|
44 |
reference_cache = kmem_cache_create("reference_cache", |
|
45 |
sizeof (reference_t), 0, NULL, NULL, NULL, NULL, NULL, 0); |
|
46 |
||
47 |
reference_history_cache = kmem_cache_create("reference_history_cache", |
|
48 |
sizeof (uint64_t), 0, NULL, NULL, NULL, NULL, NULL, 0); |
|
49 |
} |
|
50 |
||
51 |
void |
|
52 |
refcount_fini(void) |
|
53 |
{ |
|
54 |
kmem_cache_destroy(reference_cache); |
|
55 |
kmem_cache_destroy(reference_history_cache); |
|
56 |
} |
|
57 |
||
58 |
void |
|
59 |
refcount_create(refcount_t *rc) |
|
60 |
{ |
|
4787 | 61 |
mutex_init(&rc->rc_mtx, NULL, MUTEX_DEFAULT, NULL); |
789 | 62 |
list_create(&rc->rc_list, sizeof (reference_t), |
63 |
offsetof(reference_t, ref_link)); |
|
64 |
list_create(&rc->rc_removed, sizeof (reference_t), |
|
65 |
offsetof(reference_t, ref_link)); |
|
4787 | 66 |
rc->rc_count = 0; |
67 |
rc->rc_removed_count = 0; |
|
13973
4972ab336f54
3464 zfs synctask code needs restructuring
Matthew Ahrens <mahrens@delphix.com>
parents:
13952
diff
changeset
|
68 |
rc->rc_tracked = reference_tracking_enable; |
4972ab336f54
3464 zfs synctask code needs restructuring
Matthew Ahrens <mahrens@delphix.com>
parents:
13952
diff
changeset
|
69 |
} |
4972ab336f54
3464 zfs synctask code needs restructuring
Matthew Ahrens <mahrens@delphix.com>
parents:
13952
diff
changeset
|
70 |
|
4972ab336f54
3464 zfs synctask code needs restructuring
Matthew Ahrens <mahrens@delphix.com>
parents:
13952
diff
changeset
|
71 |
void |
4972ab336f54
3464 zfs synctask code needs restructuring
Matthew Ahrens <mahrens@delphix.com>
parents:
13952
diff
changeset
|
72 |
refcount_create_untracked(refcount_t *rc) |
4972ab336f54
3464 zfs synctask code needs restructuring
Matthew Ahrens <mahrens@delphix.com>
parents:
13952
diff
changeset
|
73 |
{ |
4972ab336f54
3464 zfs synctask code needs restructuring
Matthew Ahrens <mahrens@delphix.com>
parents:
13952
diff
changeset
|
74 |
refcount_create(rc); |
4972ab336f54
3464 zfs synctask code needs restructuring
Matthew Ahrens <mahrens@delphix.com>
parents:
13952
diff
changeset
|
75 |
rc->rc_tracked = B_FALSE; |
789 | 76 |
} |
77 |
||
78 |
void |
|
79 |
refcount_destroy_many(refcount_t *rc, uint64_t number) |
|
80 |
{ |
|
81 |
reference_t *ref; |
|
82 |
||
83 |
ASSERT(rc->rc_count == number); |
|
84 |
while (ref = list_head(&rc->rc_list)) { |
|
85 |
list_remove(&rc->rc_list, ref); |
|
86 |
kmem_cache_free(reference_cache, ref); |
|
87 |
} |
|
88 |
list_destroy(&rc->rc_list); |
|
89 |
||
90 |
while (ref = list_head(&rc->rc_removed)) { |
|
91 |
list_remove(&rc->rc_removed, ref); |
|
92 |
kmem_cache_free(reference_history_cache, ref->ref_removed); |
|
93 |
kmem_cache_free(reference_cache, ref); |
|
94 |
} |
|
95 |
list_destroy(&rc->rc_removed); |
|
96 |
mutex_destroy(&rc->rc_mtx); |
|
97 |
} |
|
98 |
||
99 |
void |
|
100 |
refcount_destroy(refcount_t *rc) |
|
101 |
{ |
|
102 |
refcount_destroy_many(rc, 0); |
|
103 |
} |
|
104 |
||
105 |
int |
|
106 |
refcount_is_zero(refcount_t *rc) |
|
107 |
{ |
|
108 |
return (rc->rc_count == 0); |
|
109 |
} |
|
110 |
||
111 |
int64_t |
|
112 |
refcount_count(refcount_t *rc) |
|
113 |
{ |
|
114 |
return (rc->rc_count); |
|
115 |
} |
|
116 |
||
117 |
int64_t |
|
118 |
refcount_add_many(refcount_t *rc, uint64_t number, void *holder) |
|
119 |
{ |
|
13952
7a22d0770fc8
3522 zfs module should not allow uninitialized variables
George Wilson <george.wilson@delphix.com>
parents:
12684
diff
changeset
|
120 |
reference_t *ref = NULL; |
789 | 121 |
int64_t count; |
122 |
||
13973
4972ab336f54
3464 zfs synctask code needs restructuring
Matthew Ahrens <mahrens@delphix.com>
parents:
13952
diff
changeset
|
123 |
if (rc->rc_tracked) { |
789 | 124 |
ref = kmem_cache_alloc(reference_cache, KM_SLEEP); |
125 |
ref->ref_holder = holder; |
|
126 |
ref->ref_number = number; |
|
127 |
} |
|
128 |
mutex_enter(&rc->rc_mtx); |
|
129 |
ASSERT(rc->rc_count >= 0); |
|
13973
4972ab336f54
3464 zfs synctask code needs restructuring
Matthew Ahrens <mahrens@delphix.com>
parents:
13952
diff
changeset
|
130 |
if (rc->rc_tracked) |
789 | 131 |
list_insert_head(&rc->rc_list, ref); |
132 |
rc->rc_count += number; |
|
133 |
count = rc->rc_count; |
|
134 |
mutex_exit(&rc->rc_mtx); |
|
135 |
||
136 |
return (count); |
|
137 |
} |
|
138 |
||
139 |
int64_t |
|
140 |
refcount_add(refcount_t *rc, void *holder) |
|
141 |
{ |
|
142 |
return (refcount_add_many(rc, 1, holder)); |
|
143 |
} |
|
144 |
||
145 |
int64_t |
|
146 |
refcount_remove_many(refcount_t *rc, uint64_t number, void *holder) |
|
147 |
{ |
|
148 |
reference_t *ref; |
|
149 |
int64_t count; |
|
150 |
||
151 |
mutex_enter(&rc->rc_mtx); |
|
152 |
ASSERT(rc->rc_count >= number); |
|
153 |
||
13973
4972ab336f54
3464 zfs synctask code needs restructuring
Matthew Ahrens <mahrens@delphix.com>
parents:
13952
diff
changeset
|
154 |
if (!rc->rc_tracked) { |
789 | 155 |
rc->rc_count -= number; |
156 |
count = rc->rc_count; |
|
157 |
mutex_exit(&rc->rc_mtx); |
|
158 |
return (count); |
|
159 |
} |
|
160 |
||
161 |
for (ref = list_head(&rc->rc_list); ref; |
|
162 |
ref = list_next(&rc->rc_list, ref)) { |
|
163 |
if (ref->ref_holder == holder && ref->ref_number == number) { |
|
164 |
list_remove(&rc->rc_list, ref); |
|
165 |
if (reference_history > 0) { |
|
166 |
ref->ref_removed = |
|
167 |
kmem_cache_alloc(reference_history_cache, |
|
168 |
KM_SLEEP); |
|
169 |
list_insert_head(&rc->rc_removed, ref); |
|
170 |
rc->rc_removed_count++; |
|
13973
4972ab336f54
3464 zfs synctask code needs restructuring
Matthew Ahrens <mahrens@delphix.com>
parents:
13952
diff
changeset
|
171 |
if (rc->rc_removed_count > reference_history) { |
789 | 172 |
ref = list_tail(&rc->rc_removed); |
173 |
list_remove(&rc->rc_removed, ref); |
|
174 |
kmem_cache_free(reference_history_cache, |
|
175 |
ref->ref_removed); |
|
176 |
kmem_cache_free(reference_cache, ref); |
|
177 |
rc->rc_removed_count--; |
|
178 |
} |
|
179 |
} else { |
|
180 |
kmem_cache_free(reference_cache, ref); |
|
181 |
} |
|
182 |
rc->rc_count -= number; |
|
183 |
count = rc->rc_count; |
|
184 |
mutex_exit(&rc->rc_mtx); |
|
185 |
return (count); |
|
186 |
} |
|
187 |
} |
|
188 |
panic("No such hold %p on refcount %llx", holder, |
|
189 |
(u_longlong_t)(uintptr_t)rc); |
|
190 |
return (-1); |
|
191 |
} |
|
192 |
||
193 |
int64_t |
|
194 |
refcount_remove(refcount_t *rc, void *holder) |
|
195 |
{ |
|
196 |
return (refcount_remove_many(rc, 1, holder)); |
|
197 |
} |
|
198 |
||
12684
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
199 |
void |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
200 |
refcount_transfer(refcount_t *dst, refcount_t *src) |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
201 |
{ |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
202 |
int64_t count, removed_count; |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
203 |
list_t list, removed; |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
204 |
|
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
205 |
list_create(&list, sizeof (reference_t), |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
206 |
offsetof(reference_t, ref_link)); |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
207 |
list_create(&removed, sizeof (reference_t), |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
208 |
offsetof(reference_t, ref_link)); |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
209 |
|
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
210 |
mutex_enter(&src->rc_mtx); |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
211 |
count = src->rc_count; |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
212 |
removed_count = src->rc_removed_count; |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
213 |
src->rc_count = 0; |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
214 |
src->rc_removed_count = 0; |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
215 |
list_move_tail(&list, &src->rc_list); |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
216 |
list_move_tail(&removed, &src->rc_removed); |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
217 |
mutex_exit(&src->rc_mtx); |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
218 |
|
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
219 |
mutex_enter(&dst->rc_mtx); |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
220 |
dst->rc_count += count; |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
221 |
dst->rc_removed_count += removed_count; |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
222 |
list_move_tail(&dst->rc_list, &list); |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
223 |
list_move_tail(&dst->rc_removed, &removed); |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
224 |
mutex_exit(&dst->rc_mtx); |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
225 |
|
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
226 |
list_destroy(&list); |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
227 |
list_destroy(&removed); |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
228 |
} |
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
229 |
|
397e44ebb8a9
6710343 dnode cache should register a dnode_move() callback to limit fragmentation
Tom Erickson <Tom.Erickson@Sun.COM>
parents:
12296
diff
changeset
|
230 |
#endif /* ZFS_DEBUG */ |