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.31 2003/05/23 01:08:36 grog Exp $
37 */
38
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
41
42 #include <dev/vinum/vinumhdr.h>
43
44 #ifdef VINUMDEBUG
45 #include <dev/vinum/request.h>
46 extern struct rqinfo rqinfo[];
47 extern struct rqinfo *rqip;
48 int rqinfo_size = RQINFO_SIZE; /* for debugger */
49
50 #undef longjmp /* this was defined as LongJmp */
51 #define strrchr rindex
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 /* not i386 */
93 #define LongJmp longjmp /* just use the kernel function */
94 #endif /* i386 */
95
96 /* find the base name of a path name */
97 char *
98 basename(char *file)
99 {
100 char *f = strrchr(file, '/'); /* chop off dirname if present */
101
102 if (f == NULL)
103 return file;
104 else
105 return ++f; /* skip the / */
106 }
107 #endif /* VINUMDEBUG */
108
109 #ifdef VINUMDEBUG
110 void
111 expand_table(void **table, int oldsize, int newsize, char *file, int line)
112 #else
113 void
114 expand_table(void **table, int oldsize, int newsize)
115 #endif
116 {
117 if (newsize > oldsize) {
118 int *temp;
119 int s;
120
121 s = splhigh();
122 #ifdef VINUMDEBUG
123 temp = (int *) MMalloc(newsize, file, line); /* allocate a new table */
124 #else
125 temp = (int *) Malloc(newsize); /* allocate a new table */
126 #endif
127 CHECKALLOC(temp, "vinum: Can't expand table\n");
128 bzero((char *) temp, newsize); /* clean it all out */
129 if (*table != NULL) { /* already something there, */
130 bcopy((char *) *table, (char *) temp, oldsize); /* copy it to the old table */
131 #ifdef VINUMDEBUG
132 FFree(*table, file, line);
133 #else
134 Free(*table);
135 #endif
136 }
137 *table = temp;
138 splx(s);
139 }
140 }
141
142 #ifdef VINUMDEBUG
143 #define MALLOCENTRIES 16384
144 int malloccount = 0;
145 int highwater = 0; /* highest index ever allocated */
146 struct mc malloced[MALLOCENTRIES];
147
148 #define FREECOUNT 64
149 int freecount = FREECOUNT; /* for debugger */
150 int lastfree = 0;
151 struct mc freeinfo[FREECOUNT];
152
153 int total_malloced;
154 static int mallocseq = 0;
155
156 caddr_t
157 MMalloc(int size, char *file, int line)
158 {
159 int s;
160 caddr_t result;
161 int i;
162
163 if (malloccount >= MALLOCENTRIES) { /* too many */
164 log(LOG_ERR, "vinum: can't allocate table space to trace memory allocation");
165 return 0; /* can't continue */
166 }
167 /* Wait for malloc if we can */
168 result = malloc(size,
169 M_DEVBUF,
170 curthread->td_intr_nesting_level == 0 ? M_WAITOK : M_NOWAIT);
171 if (result == NULL)
172 log(LOG_ERR, "vinum: can't allocate %d bytes from %s:%d\n", size, file, line);
173 else {
174 s = splhigh();
175 for (i = 0; i < malloccount; i++) {
176 if (((result + size) > malloced[i].address)
177 && (result < malloced[i].address + malloced[i].size)) /* overlap */
178 kdb_enter("Malloc overlap");
179 }
180 if (result) {
181 char *f = basename(file);
182
183 i = malloccount++;
184 total_malloced += size;
185 microtime(&malloced[i].time);
186 malloced[i].seq = mallocseq++;
187 malloced[i].size = size;
188 malloced[i].line = line;
189 malloced[i].address = result;
190 strlcpy(malloced[i].file, f, MCFILENAMELEN);
191 }
192 if (malloccount > highwater)
193 highwater = malloccount;
194 splx(s);
195 }
196 return result;
197 }
198
199 void
200 FFree(void *mem, char *file, int line)
201 {
202 int s;
203 int i;
204
205 s = splhigh();
206 for (i = 0; i < malloccount; i++) {
207 if ((caddr_t) mem == malloced[i].address) { /* found it */
208 bzero(mem, malloced[i].size); /* XXX */
209 free(mem, M_DEVBUF);
210 malloccount--;
211 total_malloced -= malloced[i].size;
212 if (debug & DEBUG_MEMFREE) { /* keep track of recent frees */
213 char *f = strrchr(file, '/'); /* chop off dirname if present */
214
215 if (f == NULL)
216 f = file;
217 else
218 f++; /* skip the / */
219
220 microtime(&freeinfo[lastfree].time);
221 freeinfo[lastfree].seq = malloced[i].seq;
222 freeinfo[lastfree].size = malloced[i].size;
223 freeinfo[lastfree].line = line;
224 freeinfo[lastfree].address = mem;
225 bcopy(f, freeinfo[lastfree].file, MCFILENAMELEN);
226 if (++lastfree == FREECOUNT)
227 lastfree = 0;
228 }
229 if (i < malloccount) /* more coming after */
230 bcopy(&malloced[i + 1], &malloced[i], (malloccount - i) * sizeof(struct mc));
231 splx(s);
232 return;
233 }
234 }
235 splx(s);
236 log(LOG_ERR,
237 "Freeing unallocated data at 0x%p from %s, line %d\n",
238 mem,
239 file,
240 line);
241 kdb_enter("Free");
242 }
243
244 void
245 vinum_meminfo(caddr_t data)
246 {
247 struct meminfo *m = (struct meminfo *) data;
248
249 m->mallocs = malloccount;
250 m->total_malloced = total_malloced;
251 m->malloced = malloced;
252 m->highwater = highwater;
253 }
254
255 int
256 vinum_mallocinfo(caddr_t data)
257 {
258 struct mc *m = (struct mc *) data;
259 unsigned int ent = m->seq; /* index of entry to return */
260
261 if (ent >= malloccount)
262 return ENOENT;
263 m->address = malloced[ent].address;
264 m->size = malloced[ent].size;
265 m->line = malloced[ent].line;
266 m->seq = malloced[ent].seq;
267 strlcpy(m->file, malloced[ent].file, MCFILENAMELEN);
268 return 0;
269 }
270
271 /*
272 * return the nth request trace buffer entry. This
273 * is indexed back from the current entry (which
274 * has index 0)
275 */
276 int
277 vinum_rqinfo(caddr_t data)
278 {
279 struct rqinfo *rq = (struct rqinfo *) data;
280 int ent = *(int *) data; /* 1st word is index */
281 int lastent = rqip - rqinfo; /* entry number of current entry */
282
283 if (ent >= RQINFO_SIZE) /* out of the table */
284 return ENOENT;
285 if ((ent = lastent - ent - 1) < 0)
286 ent += RQINFO_SIZE; /* roll over backwards */
287 bcopy(&rqinfo[ent], rq, sizeof(struct rqinfo));
288 return 0;
289 }
290 #endif
Cache object: f384d248e82393d00af3c4b4e4707cf6
|