Use M_INTWAIT, not M_NOWAIT. We don't really support fast interrupt
[dragonfly.git] / sys / dev / raid / vinum / vinummemory.c
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.5 2005/01/27 02:43:12 joerg 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_INTWAIT);
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