xref: /dragonfly/sys/dev/raid/vinum/vinummemory.c (revision 984263bc)
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  */
39 
40 #include <dev/vinum/vinumhdr.h>
41 
42 #ifdef VINUMDEBUG
43 #undef longjmp						    /* this was defined as LongJmp */
44 void longjmp(jmp_buf, int);				    /* the kernel doesn't define this */
45 
46 #include <dev/vinum/request.h>
47 extern struct rqinfo rqinfo[];
48 extern struct rqinfo *rqip;
49 int rqinfo_size = RQINFO_SIZE;				    /* for debugger */
50 
51 #ifdef __i386__						    /* check for validity */
52 void
53 LongJmp(jmp_buf buf, int retval)
54 {
55 /*
56    * longjmp is not documented, not even jmp_buf.
57    * This is what's in i386/i386/support.s:
58    * ENTRY(longjmp)
59    *    movl    4(%esp),%eax
60    *    movl    (%eax),%ebx                      restore ebx
61    *    movl    4(%eax),%esp                     restore esp
62    *    movl    8(%eax),%ebp                     restore ebp
63    *    movl    12(%eax),%esi                    restore esi
64    *    movl    16(%eax),%edi                    restore edi
65    *    movl    20(%eax),%edx                    get rta
66    *    movl    %edx,(%esp)                      put in return frame
67    *    xorl    %eax,%eax                        return(1);
68    *    incl    %eax
69    *    ret
70    *
71    * from which we deduce the structure of jmp_buf:
72  */
73     struct JmpBuf {
74 	int jb_ebx;
75 	int jb_esp;
76 	int jb_ebp;
77 	int jb_esi;
78 	int jb_edi;
79 	int jb_eip;
80     };
81 
82     struct JmpBuf *jb = (struct JmpBuf *) buf;
83 
84     if ((jb->jb_esp < 0xc0000000)
85 	|| (jb->jb_ebp < 0xc0000000)
86 	|| (jb->jb_eip < 0xc0000000))
87 	panic("Invalid longjmp");
88     longjmp(buf, retval);
89 }
90 
91 #else
92 #define LongJmp longjmp					    /* just use the kernel function */
93 #endif
94 #endif
95 
96 /* find the base name of a path name */
97 char *
98 basename(char *file)
99 {
100     char *f = rindex(file, '/');			    /* chop off dirname if present */
101 
102     if (f == NULL)
103 	return file;
104     else
105 	return ++f;					    /* skip the / */
106 }
107 
108 void
109 expand_table(void **table, int oldsize, int newsize)
110 {
111     if (newsize > oldsize) {
112 	int *temp;
113 	int s;
114 
115 	s = splhigh();
116 	temp = (int *) Malloc(newsize);			    /* allocate a new table */
117 	CHECKALLOC(temp, "vinum: Can't expand table\n");
118 	bzero((char *) temp, newsize);			    /* clean it all out */
119 	if (*table != NULL) {				    /* already something there, */
120 	    bcopy((char *) *table, (char *) temp, oldsize); /* copy it to the old table */
121 	    Free(*table);
122 	}
123 	*table = temp;
124 	splx(s);
125     }
126 }
127 
128 #if VINUMDEBUG						    /* XXX debug */
129 #define MALLOCENTRIES 16384
130 int malloccount = 0;
131 int highwater = 0;					    /* highest index ever allocated */
132 struct mc malloced[MALLOCENTRIES];
133 
134 #define FREECOUNT 64
135 int freecount = FREECOUNT;				    /* for debugger */
136 int lastfree = 0;
137 struct mc freeinfo[FREECOUNT];
138 
139 int total_malloced;
140 static int mallocseq = 0;
141 
142 caddr_t
143 MMalloc(int size, char *file, int line)
144 {
145     int s;
146     caddr_t result;
147     int i;
148 
149     if (malloccount >= MALLOCENTRIES) {			    /* too many */
150 	log(LOG_ERR, "vinum: can't allocate table space to trace memory allocation");
151 	return 0;					    /* can't continue */
152     }
153     /* Wait for malloc if we can */
154     result = malloc(size, M_DEVBUF, intr_nesting_level == 0 ? M_WAITOK : M_NOWAIT);
155     if (result == NULL)
156 	log(LOG_ERR, "vinum: can't allocate %d bytes from %s:%d\n", size, file, line);
157     else {
158 	s = splhigh();
159 	for (i = 0; i < malloccount; i++) {
160 	    if (((result + size) > malloced[i].address)
161 		&& (result < malloced[i].address + malloced[i].size)) /* overlap */
162 		Debugger("Malloc overlap");
163 	}
164 	if (result) {
165 	    char *f = basename(file);
166 
167 	    i = malloccount++;
168 	    total_malloced += size;
169 	    microtime(&malloced[i].time);
170 	    malloced[i].seq = mallocseq++;
171 	    malloced[i].size = size;
172 	    malloced[i].line = line;
173 	    malloced[i].address = result;
174 	    bcopy(f, malloced[i].file, min(strlen(f), MCFILENAMELEN - 1));
175 	    malloced[i].file[MCFILENAMELEN - 1] = '\0';
176 	}
177 	if (malloccount > highwater)
178 	    highwater = malloccount;
179 	splx(s);
180     }
181     return result;
182 }
183 
184 void
185 FFree(void *mem, char *file, int line)
186 {
187     int s;
188     int i;
189 
190     s = splhigh();
191     for (i = 0; i < malloccount; i++) {
192 	if ((caddr_t) mem == malloced[i].address) {	    /* found it */
193 	    bzero(mem, malloced[i].size);		    /* XXX */
194 	    free(mem, M_DEVBUF);
195 	    malloccount--;
196 	    total_malloced -= malloced[i].size;
197 	    if (debug & DEBUG_MEMFREE) {		    /* keep track of recent frees */
198 		char *f = rindex(file, '/');		    /* chop off dirname if present */
199 
200 		if (f == NULL)
201 		    f = file;
202 		else
203 		    f++;				    /* skip the / */
204 
205 		microtime(&freeinfo[lastfree].time);
206 		freeinfo[lastfree].seq = malloced[i].seq;
207 		freeinfo[lastfree].size = malloced[i].size;
208 		freeinfo[lastfree].line = line;
209 		freeinfo[lastfree].address = mem;
210 		bcopy(f, freeinfo[lastfree].file, min(strlen(f), MCFILENAMELEN - 1));
211 		freeinfo[lastfree].file[MCFILENAMELEN - 1] = '\0';
212 		if (++lastfree == FREECOUNT)
213 		    lastfree = 0;
214 	    }
215 	    if (i < malloccount)			    /* more coming after */
216 		bcopy(&malloced[i + 1], &malloced[i], (malloccount - i) * sizeof(struct mc));
217 	    splx(s);
218 	    return;
219 	}
220     }
221     splx(s);
222     log(LOG_ERR,
223 	"Freeing unallocated data at 0x%p from %s, line %d\n",
224 	mem,
225 	file,
226 	line);
227     Debugger("Free");
228 }
229 
230 void
231 vinum_meminfo(caddr_t data)
232 {
233     struct meminfo *m = (struct meminfo *) data;
234 
235     m->mallocs = malloccount;
236     m->total_malloced = total_malloced;
237     m->malloced = malloced;
238     m->highwater = highwater;
239 }
240 
241 int
242 vinum_mallocinfo(caddr_t data)
243 {
244     struct mc *m = (struct mc *) data;
245     unsigned int ent = m->seq;				    /* index of entry to return */
246 
247     if (ent >= malloccount)
248 	return ENOENT;
249     m->address = malloced[ent].address;
250     m->size = malloced[ent].size;
251     m->line = malloced[ent].line;
252     m->seq = malloced[ent].seq;
253     bcopy(malloced[ent].file, m->file, MCFILENAMELEN);
254     return 0;
255 }
256 
257 /*
258  * return the nth request trace buffer entry.  This
259  * is indexed back from the current entry (which
260  * has index 0)
261  */
262 int
263 vinum_rqinfo(caddr_t data)
264 {
265     struct rqinfo *rq = (struct rqinfo *) data;
266     int ent = *(int *) data;				    /* 1st word is index */
267     int lastent = rqip - rqinfo;			    /* entry number of current entry */
268 
269     if (ent >= RQINFO_SIZE)				    /* out of the table */
270 	return ENOENT;
271     if ((ent = lastent - ent - 1) < 0)
272 	ent += RQINFO_SIZE;				    /* roll over backwards */
273     bcopy(&rqinfo[ent], rq, sizeof(struct rqinfo));
274     return 0;
275 }
276 #endif
277