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