1 /*- 2 * Copyright (c) 1997, 1998 3 * Nan Yang Computer Services Limited. All rights reserved. 4 * 5 * This software is distributed under the so-called ``Berkeley 6 * License'': 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Nan Yang Computer 19 * Services Limited. 20 * 4. Neither the name of the Company nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * This software is provided ``as is'', and any express or implied 25 * warranties, including, but not limited to, the implied warranties of 26 * merchantability and fitness for a particular purpose are disclaimed. 27 * In no event shall the company or contributors be liable for any 28 * direct, indirect, incidental, special, exemplary, or consequential 29 * damages (including, but not limited to, procurement of substitute 30 * goods or services; loss of use, data, or profits; or business 31 * interruption) however caused and on any theory of liability, whether 32 * in contract, strict liability, or tort (including negligence or 33 * otherwise) arising in any way out of the use of this software, even if 34 * advised of the possibility of such damage. 35 * 36 * $Id: vinummemory.c,v 1.25 2000/05/04 01:57:48 grog Exp grog $ 37 * $FreeBSD: src/sys/dev/vinum/vinummemory.c,v 1.22.2.1 2000/06/02 04:26:11 grog Exp $ 38 * $DragonFly: src/sys/dev/raid/vinum/vinummemory.c,v 1.4 2003/08/07 21:17:09 dillon Exp $ 39 */ 40 41 #include "vinumhdr.h" 42 43 #ifdef VINUMDEBUG 44 #undef longjmp /* this was defined as LongJmp */ 45 void longjmp(jmp_buf, int); /* the kernel doesn't define this */ 46 47 #include "request.h" 48 extern struct rqinfo rqinfo[]; 49 extern struct rqinfo *rqip; 50 int rqinfo_size = RQINFO_SIZE; /* for debugger */ 51 52 #ifdef __i386__ /* check for validity */ 53 void 54 LongJmp(jmp_buf buf, int retval) 55 { 56 /* 57 * longjmp is not documented, not even jmp_buf. 58 * This is what's in i386/i386/support.s: 59 * ENTRY(longjmp) 60 * movl 4(%esp),%eax 61 * movl (%eax),%ebx restore ebx 62 * movl 4(%eax),%esp restore esp 63 * movl 8(%eax),%ebp restore ebp 64 * movl 12(%eax),%esi restore esi 65 * movl 16(%eax),%edi restore edi 66 * movl 20(%eax),%edx get rta 67 * movl %edx,(%esp) put in return frame 68 * xorl %eax,%eax return(1); 69 * incl %eax 70 * ret 71 * 72 * from which we deduce the structure of jmp_buf: 73 */ 74 struct JmpBuf { 75 int jb_ebx; 76 int jb_esp; 77 int jb_ebp; 78 int jb_esi; 79 int jb_edi; 80 int jb_eip; 81 }; 82 83 struct JmpBuf *jb = (struct JmpBuf *) buf; 84 85 if ((jb->jb_esp < 0xc0000000) 86 || (jb->jb_ebp < 0xc0000000) 87 || (jb->jb_eip < 0xc0000000)) 88 panic("Invalid longjmp"); 89 longjmp(buf, retval); 90 } 91 92 #else 93 #define LongJmp longjmp /* just use the kernel function */ 94 #endif 95 #endif 96 97 /* find the base name of a path name */ 98 char * 99 basename(char *file) 100 { 101 char *f = rindex(file, '/'); /* chop off dirname if present */ 102 103 if (f == NULL) 104 return file; 105 else 106 return ++f; /* skip the / */ 107 } 108 109 void 110 expand_table(void **table, int oldsize, int newsize) 111 { 112 if (newsize > oldsize) { 113 int *temp; 114 int s; 115 116 s = splhigh(); 117 temp = (int *) Malloc(newsize); /* allocate a new table */ 118 CHECKALLOC(temp, "vinum: Can't expand table\n"); 119 bzero((char *) temp, newsize); /* clean it all out */ 120 if (*table != NULL) { /* already something there, */ 121 bcopy((char *) *table, (char *) temp, oldsize); /* copy it to the old table */ 122 Free(*table); 123 } 124 *table = temp; 125 splx(s); 126 } 127 } 128 129 #if VINUMDEBUG /* XXX debug */ 130 #define MALLOCENTRIES 16384 131 int malloccount = 0; 132 int highwater = 0; /* highest index ever allocated */ 133 struct mc malloced[MALLOCENTRIES]; 134 135 #define FREECOUNT 64 136 int freecount = FREECOUNT; /* for debugger */ 137 int lastfree = 0; 138 struct mc freeinfo[FREECOUNT]; 139 140 int total_malloced; 141 static int mallocseq = 0; 142 143 caddr_t 144 MMalloc(int size, char *file, int line) 145 { 146 int s; 147 caddr_t result; 148 int i; 149 150 if (malloccount >= MALLOCENTRIES) { /* too many */ 151 log(LOG_ERR, "vinum: can't allocate table space to trace memory allocation"); 152 return 0; /* can't continue */ 153 } 154 /* Wait for malloc if we can */ 155 result = malloc(size, M_DEVBUF, mycpu->gd_intr_nesting_level == 0 ? M_WAITOK : M_NOWAIT); 156 if (result == NULL) 157 log(LOG_ERR, "vinum: can't allocate %d bytes from %s:%d\n", size, file, line); 158 else { 159 s = splhigh(); 160 for (i = 0; i < malloccount; i++) { 161 if (((result + size) > malloced[i].address) 162 && (result < malloced[i].address + malloced[i].size)) /* overlap */ 163 Debugger("Malloc overlap"); 164 } 165 if (result) { 166 char *f = basename(file); 167 168 i = malloccount++; 169 total_malloced += size; 170 microtime(&malloced[i].time); 171 malloced[i].seq = mallocseq++; 172 malloced[i].size = size; 173 malloced[i].line = line; 174 malloced[i].address = result; 175 bcopy(f, malloced[i].file, min(strlen(f), MCFILENAMELEN - 1)); 176 malloced[i].file[MCFILENAMELEN - 1] = '\0'; 177 } 178 if (malloccount > highwater) 179 highwater = malloccount; 180 splx(s); 181 } 182 return result; 183 } 184 185 void 186 FFree(void *mem, char *file, int line) 187 { 188 int s; 189 int i; 190 191 s = splhigh(); 192 for (i = 0; i < malloccount; i++) { 193 if ((caddr_t) mem == malloced[i].address) { /* found it */ 194 bzero(mem, malloced[i].size); /* XXX */ 195 free(mem, M_DEVBUF); 196 malloccount--; 197 total_malloced -= malloced[i].size; 198 if (debug & DEBUG_MEMFREE) { /* keep track of recent frees */ 199 char *f = rindex(file, '/'); /* chop off dirname if present */ 200 201 if (f == NULL) 202 f = file; 203 else 204 f++; /* skip the / */ 205 206 microtime(&freeinfo[lastfree].time); 207 freeinfo[lastfree].seq = malloced[i].seq; 208 freeinfo[lastfree].size = malloced[i].size; 209 freeinfo[lastfree].line = line; 210 freeinfo[lastfree].address = mem; 211 bcopy(f, freeinfo[lastfree].file, min(strlen(f), MCFILENAMELEN - 1)); 212 freeinfo[lastfree].file[MCFILENAMELEN - 1] = '\0'; 213 if (++lastfree == FREECOUNT) 214 lastfree = 0; 215 } 216 if (i < malloccount) /* more coming after */ 217 bcopy(&malloced[i + 1], &malloced[i], (malloccount - i) * sizeof(struct mc)); 218 splx(s); 219 return; 220 } 221 } 222 splx(s); 223 log(LOG_ERR, 224 "Freeing unallocated data at 0x%p from %s, line %d\n", 225 mem, 226 file, 227 line); 228 Debugger("Free"); 229 } 230 231 void 232 vinum_meminfo(caddr_t data) 233 { 234 struct meminfo *m = (struct meminfo *) data; 235 236 m->mallocs = malloccount; 237 m->total_malloced = total_malloced; 238 m->malloced = malloced; 239 m->highwater = highwater; 240 } 241 242 int 243 vinum_mallocinfo(caddr_t data) 244 { 245 struct mc *m = (struct mc *) data; 246 unsigned int ent = m->seq; /* index of entry to return */ 247 248 if (ent >= malloccount) 249 return ENOENT; 250 m->address = malloced[ent].address; 251 m->size = malloced[ent].size; 252 m->line = malloced[ent].line; 253 m->seq = malloced[ent].seq; 254 bcopy(malloced[ent].file, m->file, MCFILENAMELEN); 255 return 0; 256 } 257 258 /* 259 * return the nth request trace buffer entry. This 260 * is indexed back from the current entry (which 261 * has index 0) 262 */ 263 int 264 vinum_rqinfo(caddr_t data) 265 { 266 struct rqinfo *rq = (struct rqinfo *) data; 267 int ent = *(int *) data; /* 1st word is index */ 268 int lastent = rqip - rqinfo; /* entry number of current entry */ 269 270 if (ent >= RQINFO_SIZE) /* out of the table */ 271 return ENOENT; 272 if ((ent = lastent - ent - 1) < 0) 273 ent += RQINFO_SIZE; /* roll over backwards */ 274 bcopy(&rqinfo[ent], rq, sizeof(struct rqinfo)); 275 return 0; 276 } 277 #endif 278