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