]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/gnu/fs/xfs/FreeBSD/support/ktrace.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / gnu / fs / xfs / FreeBSD / support / ktrace.c
1 /*
2  * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write the Free Software Foundation,
16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 #include <xfs.h>
19
20 static kmem_zone_t *ktrace_hdr_zone;
21 static kmem_zone_t *ktrace_ent_zone;
22 static int          ktrace_zentries;
23 static struct mtx   wrap_lock;
24
25 void
26 ktrace_init(int zentries)
27 {
28         ktrace_zentries = zentries;
29
30         ktrace_hdr_zone = kmem_zone_init(sizeof(ktrace_t),
31                                         "ktrace_hdr");
32         ASSERT(ktrace_hdr_zone);
33
34         ktrace_ent_zone = kmem_zone_init(ktrace_zentries
35                                         * sizeof(ktrace_entry_t),
36                                         "ktrace_ent");
37         ASSERT(ktrace_ent_zone);
38
39         mtx_init(&wrap_lock, "xfsktr", NULL, MTX_DEF);
40 }
41
42 void
43 ktrace_uninit(void)
44 {
45         kmem_zone_destroy(ktrace_hdr_zone);
46         kmem_zone_destroy(ktrace_ent_zone);
47
48         mtx_destroy(&wrap_lock);
49 }
50
51 /*
52  * ktrace_alloc()
53  *
54  * Allocate a ktrace header and enough buffering for the given
55  * number of entries.
56  */
57 ktrace_t *
58 ktrace_alloc(int nentries, int sleep)
59 {
60         ktrace_t        *ktp;
61         ktrace_entry_t  *ktep;
62
63         ktp = (ktrace_t*)kmem_zone_alloc(ktrace_hdr_zone, sleep);
64
65         if (ktp == (ktrace_t*)NULL) {
66                 /*
67                  * KM_SLEEP callers don't expect failure.
68                  */
69                 if (sleep & KM_SLEEP)
70                         panic("ktrace_alloc: NULL memory on KM_SLEEP request!");
71
72                 return NULL;
73         }
74
75         /*
76          * Special treatment for buffers with the ktrace_zentries entries
77          */
78         if (nentries == ktrace_zentries) {
79                 ktep = (ktrace_entry_t*)kmem_zone_zalloc(ktrace_ent_zone,
80                                                             sleep);
81         } else {
82                 ktep = (ktrace_entry_t*)kmem_zalloc((nentries * sizeof(*ktep)),
83                                                             sleep);
84         }
85
86         if (ktep == NULL) {
87                 /*
88                  * KM_SLEEP callers don't expect failure.
89                  */
90                 if (sleep & KM_SLEEP)
91                         panic("ktrace_alloc: NULL memory on KM_SLEEP request!");
92
93                 kmem_free(ktp, sizeof(*ktp));
94
95                 return NULL;
96         }
97
98         spinlock_init(&(ktp->kt_lock), "kt_lock");
99
100         ktp->kt_entries  = ktep;
101         ktp->kt_nentries = nentries;
102         ktp->kt_index    = 0;
103         ktp->kt_rollover = 0;
104         return ktp;
105 }
106
107
108 /*
109  * ktrace_free()
110  *
111  * Free up the ktrace header and buffer.  It is up to the caller
112  * to ensure that no-one is referencing it.
113  */
114 void
115 ktrace_free(ktrace_t *ktp)
116 {
117         int     entries_size;
118
119         if (ktp == (ktrace_t *)NULL)
120                 return;
121
122         spinlock_destroy(&ktp->kt_lock);
123
124         /*
125          * Special treatment for the Vnode trace buffer.
126          */
127         if (ktp->kt_nentries == ktrace_zentries) {
128                 kmem_zone_free(ktrace_ent_zone, ktp->kt_entries);
129         } else {
130                 entries_size = (int)(ktp->kt_nentries * sizeof(ktrace_entry_t));
131
132                 kmem_free(ktp->kt_entries, entries_size);
133         }
134
135         kmem_zone_free(ktrace_hdr_zone, ktp);
136 }
137
138
139 /*
140  * Enter the given values into the "next" entry in the trace buffer.
141  * kt_index is always the index of the next entry to be filled.
142  */
143 void
144 ktrace_enter(
145         ktrace_t        *ktp,
146         void            *val0,
147         void            *val1,
148         void            *val2,
149         void            *val3,
150         void            *val4,
151         void            *val5,
152         void            *val6,
153         void            *val7,
154         void            *val8,
155         void            *val9,
156         void            *val10,
157         void            *val11,
158         void            *val12,
159         void            *val13,
160         void            *val14,
161         void            *val15)
162 {
163         int             index;
164         ktrace_entry_t  *ktep;
165
166         ASSERT(ktp != NULL);
167
168         /*
169          * Grab an entry by pushing the index up to the next one.
170          */
171         mtx_lock(&wrap_lock);
172         index = ktp->kt_index;
173         if (++ktp->kt_index == ktp->kt_nentries)
174                 ktp->kt_index = 0;
175         mtx_unlock(&wrap_lock);
176
177         if (!ktp->kt_rollover && index == ktp->kt_nentries - 1)
178                 ktp->kt_rollover = 1;
179
180         ASSERT((index >= 0) && (index < ktp->kt_nentries));
181
182         ktep = &(ktp->kt_entries[index]);
183
184         ktep->val[0]  = val0;
185         ktep->val[1]  = val1;
186         ktep->val[2]  = val2;
187         ktep->val[3]  = val3;
188         ktep->val[4]  = val4;
189         ktep->val[5]  = val5;
190         ktep->val[6]  = val6;
191         ktep->val[7]  = val7;
192         ktep->val[8]  = val8;
193         ktep->val[9]  = val9;
194         ktep->val[10] = val10;
195         ktep->val[11] = val11;
196         ktep->val[12] = val12;
197         ktep->val[13] = val13;
198         ktep->val[14] = val14;
199         ktep->val[15] = val15;
200 }
201
202 /*
203  * Return the number of entries in the trace buffer.
204  */
205 int
206 ktrace_nentries(
207         ktrace_t        *ktp)
208 {
209         if (ktp == NULL) {
210                 return 0;
211         }
212
213         return (ktp->kt_rollover ? ktp->kt_nentries : ktp->kt_index);
214 }
215
216 /*
217  * ktrace_first()
218  *
219  * This is used to find the start of the trace buffer.
220  * In conjunction with ktrace_next() it can be used to
221  * iterate through the entire trace buffer.  This code does
222  * not do any locking because it is assumed that it is called
223  * from the debugger.
224  *
225  * The caller must pass in a pointer to a ktrace_snap
226  * structure in which we will keep some state used to
227  * iterate through the buffer.  This state must not touched
228  * by any code outside of this module.
229  */
230 ktrace_entry_t *
231 ktrace_first(ktrace_t   *ktp, ktrace_snap_t     *ktsp)
232 {
233         ktrace_entry_t  *ktep;
234         int             index;
235         int             nentries;
236
237         if (ktp->kt_rollover)
238                 index = ktp->kt_index;
239         else
240                 index = 0;
241
242         ktsp->ks_start = index;
243         ktep = &(ktp->kt_entries[index]);
244
245         nentries = ktrace_nentries(ktp);
246         index++;
247         if (index < nentries) {
248                 ktsp->ks_index = index;
249         } else {
250                 ktsp->ks_index = 0;
251                 if (index > nentries)
252                         ktep = NULL;
253         }
254         return ktep;
255 }
256
257 /*
258  * ktrace_next()
259  *
260  * This is used to iterate through the entries of the given
261  * trace buffer.  The caller must pass in the ktrace_snap_t
262  * structure initialized by ktrace_first().  The return value
263  * will be either a pointer to the next ktrace_entry or NULL
264  * if all of the entries have been traversed.
265  */
266 ktrace_entry_t *
267 ktrace_next(
268         ktrace_t        *ktp,
269         ktrace_snap_t   *ktsp)
270 {
271         int             index;
272         ktrace_entry_t  *ktep;
273
274         index = ktsp->ks_index;
275         if (index == ktsp->ks_start) {
276                 ktep = NULL;
277         } else {
278                 ktep = &ktp->kt_entries[index];
279         }
280
281         index++;
282         if (index == ktrace_nentries(ktp)) {
283                 ktsp->ks_index = 0;
284         } else {
285                 ktsp->ks_index = index;
286         }
287
288         return ktep;
289 }
290
291 /*
292  * ktrace_skip()
293  *
294  * Skip the next "count" entries and return the entry after that.
295  * Return NULL if this causes us to iterate past the beginning again.
296  */
297 ktrace_entry_t *
298 ktrace_skip(
299         ktrace_t        *ktp,
300         int             count,
301         ktrace_snap_t   *ktsp)
302 {
303         int             index;
304         int             new_index;
305         ktrace_entry_t  *ktep;
306         int             nentries = ktrace_nentries(ktp);
307
308         index = ktsp->ks_index;
309         new_index = index + count;
310         while (new_index >= nentries) {
311                 new_index -= nentries;
312         }
313         if (index == ktsp->ks_start) {
314                 /*
315                  * We've iterated around to the start, so we're done.
316                  */
317                 ktep = NULL;
318         } else if ((new_index < index) && (index < ktsp->ks_index)) {
319                 /*
320                  * We've skipped past the start again, so we're done.
321                  */
322                 ktep = NULL;
323                 ktsp->ks_index = ktsp->ks_start;
324         } else {
325                 ktep = &(ktp->kt_entries[new_index]);
326                 new_index++;
327                 if (new_index == nentries) {
328                         ktsp->ks_index = 0;
329                 } else {
330                         ktsp->ks_index = new_index;
331                 }
332         }
333         return ktep;
334 }