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