1 /* 2 * Copyright (c) 1987, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)kern_malloc.c 8.3 (Berkeley) 1/4/94 34 * $Id: kern_malloc.c,v 1.23 1996/05/18 22:33:13 dyson Exp $ 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/proc.h> 40 #include <sys/kernel.h> 41 #include <sys/malloc.h> 42 #include <sys/mbuf.h> 43 #include <sys/vmmeter.h> 44 45 #include <vm/vm.h> 46 #include <vm/vm_param.h> 47 #include <vm/vm_kern.h> 48 #include <vm/vm_extern.h> 49 50 static void kmeminit __P((void *)); 51 SYSINIT(kmem, SI_SUB_KMEM, SI_ORDER_FIRST, kmeminit, NULL) 52 53 static struct kmembuckets bucket[MINBUCKET + 16]; 54 struct kmemstats kmemstats[M_LAST]; 55 struct kmemusage *kmemusage; 56 char *kmembase, *kmemlimit; 57 char *memname[] = INITKMEMNAMES; 58 59 #ifdef DIAGNOSTIC 60 /* 61 * This structure provides a set of masks to catch unaligned frees. 62 */ 63 static long addrmask[] = { 0, 64 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 65 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 66 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 67 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff, 68 }; 69 70 /* 71 * The WEIRD_ADDR is used as known text to copy into free objects so 72 * that modifications after frees can be detected. 73 */ 74 #define WEIRD_ADDR 0xdeadc0de 75 #define MAX_COPY 64 76 77 /* 78 * Normally the first word of the structure is used to hold the list 79 * pointer for free objects. However, when running with diagnostics, 80 * we use the third and fourth fields, so as to catch modifications 81 * in the most commonly trashed first two words. 82 */ 83 struct freelist { 84 long spare0; 85 short type; 86 long spare1; 87 caddr_t next; 88 }; 89 #else /* !DIAGNOSTIC */ 90 struct freelist { 91 caddr_t next; 92 }; 93 #endif /* DIAGNOSTIC */ 94 95 /* 96 * Allocate a block of memory 97 */ 98 void * 99 malloc(size, type, flags) 100 unsigned long size; 101 int type, flags; 102 { 103 register struct kmembuckets *kbp; 104 register struct kmemusage *kup; 105 register struct freelist *freep; 106 long indx, npg, allocsize; 107 int s; 108 caddr_t va, cp, savedlist; 109 #ifdef DIAGNOSTIC 110 long *end, *lp; 111 int copysize; 112 char *savedtype; 113 #endif 114 #ifdef KMEMSTATS 115 register struct kmemstats *ksp = &kmemstats[type]; 116 117 if (((unsigned long)type) > M_LAST) 118 panic("malloc - bogus type"); 119 #endif 120 indx = BUCKETINDX(size); 121 kbp = &bucket[indx]; 122 s = splhigh(); 123 #ifdef KMEMSTATS 124 while (ksp->ks_memuse >= ksp->ks_limit) { 125 if (flags & M_NOWAIT) { 126 splx(s); 127 return ((void *) NULL); 128 } 129 if (ksp->ks_limblocks < 65535) 130 ksp->ks_limblocks++; 131 tsleep((caddr_t)ksp, PSWP+2, memname[type], 0); 132 } 133 ksp->ks_size |= 1 << indx; 134 #endif 135 #ifdef DIAGNOSTIC 136 copysize = 1 << indx < MAX_COPY ? 1 << indx : MAX_COPY; 137 #endif 138 if (kbp->kb_next == NULL) { 139 kbp->kb_last = NULL; 140 if (size > MAXALLOCSAVE) 141 allocsize = roundup(size, PAGE_SIZE); 142 else 143 allocsize = 1 << indx; 144 npg = btoc(allocsize); 145 va = (caddr_t) kmem_malloc(kmem_map, (vm_size_t)ctob(npg), flags); 146 if (va == NULL) { 147 splx(s); 148 return ((void *) NULL); 149 } 150 #ifdef KMEMSTATS 151 kbp->kb_total += kbp->kb_elmpercl; 152 #endif 153 kup = btokup(va); 154 kup->ku_indx = indx; 155 if (allocsize > MAXALLOCSAVE) { 156 if (npg > 65535) 157 panic("malloc: allocation too large"); 158 kup->ku_pagecnt = npg; 159 #ifdef KMEMSTATS 160 ksp->ks_memuse += allocsize; 161 #endif 162 goto out; 163 } 164 #ifdef KMEMSTATS 165 kup->ku_freecnt = kbp->kb_elmpercl; 166 kbp->kb_totalfree += kbp->kb_elmpercl; 167 #endif 168 /* 169 * Just in case we blocked while allocating memory, 170 * and someone else also allocated memory for this 171 * bucket, don't assume the list is still empty. 172 */ 173 savedlist = kbp->kb_next; 174 kbp->kb_next = cp = va + (npg * PAGE_SIZE) - allocsize; 175 for (;;) { 176 freep = (struct freelist *)cp; 177 #ifdef DIAGNOSTIC 178 /* 179 * Copy in known text to detect modification 180 * after freeing. 181 */ 182 end = (long *)&cp[copysize]; 183 for (lp = (long *)cp; lp < end; lp++) 184 *lp = WEIRD_ADDR; 185 freep->type = M_FREE; 186 #endif /* DIAGNOSTIC */ 187 if (cp <= va) 188 break; 189 cp -= allocsize; 190 freep->next = cp; 191 } 192 freep->next = savedlist; 193 if (kbp->kb_last == NULL) 194 kbp->kb_last = (caddr_t)freep; 195 } 196 va = kbp->kb_next; 197 kbp->kb_next = ((struct freelist *)va)->next; 198 #ifdef DIAGNOSTIC 199 freep = (struct freelist *)va; 200 savedtype = (unsigned)freep->type < M_LAST ? 201 memname[freep->type] : "???"; 202 if (kbp->kb_next && 203 !kernacc(kbp->kb_next, sizeof(struct freelist), 0)) { 204 printf("%s of object %p size %ld %s %s (invalid addr %p)\n", 205 "Data modified on freelist: word 2.5", va, size, 206 "previous type", savedtype, kbp->kb_next); 207 kbp->kb_next = NULL; 208 } 209 #if BYTE_ORDER == BIG_ENDIAN 210 freep->type = WEIRD_ADDR >> 16; 211 #endif 212 #if BYTE_ORDER == LITTLE_ENDIAN 213 freep->type = (short)WEIRD_ADDR; 214 #endif 215 if (((long)(&freep->next)) & 0x2) 216 freep->next = (caddr_t)((WEIRD_ADDR >> 16)|(WEIRD_ADDR << 16)); 217 else 218 freep->next = (caddr_t)WEIRD_ADDR; 219 end = (long *)&va[copysize]; 220 for (lp = (long *)va; lp < end; lp++) { 221 if (*lp == WEIRD_ADDR) 222 continue; 223 printf("%s %d of object %p size %ld %s %s (0x%lx != 0x%x)\n", 224 "Data modified on freelist: word", lp - (long *)va, 225 va, size, "previous type", savedtype, *lp, WEIRD_ADDR); 226 break; 227 } 228 freep->spare0 = 0; 229 #endif /* DIAGNOSTIC */ 230 #ifdef KMEMSTATS 231 kup = btokup(va); 232 if (kup->ku_indx != indx) 233 panic("malloc: wrong bucket"); 234 if (kup->ku_freecnt == 0) 235 panic("malloc: lost data"); 236 kup->ku_freecnt--; 237 kbp->kb_totalfree--; 238 ksp->ks_memuse += 1 << indx; 239 out: 240 kbp->kb_calls++; 241 ksp->ks_inuse++; 242 ksp->ks_calls++; 243 if (ksp->ks_memuse > ksp->ks_maxused) 244 ksp->ks_maxused = ksp->ks_memuse; 245 #else 246 out: 247 #endif 248 splx(s); 249 return ((void *) va); 250 } 251 252 /* 253 * Free a block of memory allocated by malloc. 254 */ 255 void 256 free(addr, type) 257 void *addr; 258 int type; 259 { 260 register struct kmembuckets *kbp; 261 register struct kmemusage *kup; 262 register struct freelist *freep; 263 long size; 264 int s; 265 #ifdef DIAGNOSTIC 266 struct freelist *fp; 267 long *end, *lp, alloc, copysize; 268 #endif 269 #ifdef KMEMSTATS 270 register struct kmemstats *ksp = &kmemstats[type]; 271 #endif 272 273 #ifdef DIAGNOSTIC 274 if ((char *)addr < kmembase || (char *)addr >= kmemlimit) { 275 panic("free: address 0x%x out of range", addr); 276 } 277 if ((u_long)type > M_LAST) { 278 panic("free: type %d out of range", type); 279 } 280 #endif 281 kup = btokup(addr); 282 size = 1 << kup->ku_indx; 283 kbp = &bucket[kup->ku_indx]; 284 s = splhigh(); 285 #ifdef DIAGNOSTIC 286 /* 287 * Check for returns of data that do not point to the 288 * beginning of the allocation. 289 */ 290 if (size > PAGE_SIZE) 291 alloc = addrmask[BUCKETINDX(PAGE_SIZE)]; 292 else 293 alloc = addrmask[kup->ku_indx]; 294 if (((u_long)addr & alloc) != 0) 295 panic("free: unaligned addr 0x%x, size %d, type %s, mask %d", 296 addr, size, memname[type], alloc); 297 #endif /* DIAGNOSTIC */ 298 if (size > MAXALLOCSAVE) { 299 kmem_free(kmem_map, (vm_offset_t)addr, ctob(kup->ku_pagecnt)); 300 #ifdef KMEMSTATS 301 size = kup->ku_pagecnt << PAGE_SHIFT; 302 ksp->ks_memuse -= size; 303 kup->ku_indx = 0; 304 kup->ku_pagecnt = 0; 305 if (ksp->ks_memuse + size >= ksp->ks_limit && 306 ksp->ks_memuse < ksp->ks_limit) 307 wakeup((caddr_t)ksp); 308 ksp->ks_inuse--; 309 kbp->kb_total -= 1; 310 #endif 311 splx(s); 312 return; 313 } 314 freep = (struct freelist *)addr; 315 #ifdef DIAGNOSTIC 316 /* 317 * Check for multiple frees. Use a quick check to see if 318 * it looks free before laboriously searching the freelist. 319 */ 320 if (freep->spare0 == WEIRD_ADDR) { 321 fp = (struct freelist *)kbp->kb_next; 322 while (fp) { 323 if (fp->spare0 != WEIRD_ADDR) { 324 printf("trashed free item %p\n", fp); 325 panic("free: free item modified"); 326 } else if (addr == (caddr_t)fp) { 327 printf("multiple freed item %p\n", addr); 328 panic("free: multiple free"); 329 } 330 fp = (struct freelist *)fp->next; 331 } 332 } 333 /* 334 * Copy in known text to detect modification after freeing 335 * and to make it look free. Also, save the type being freed 336 * so we can list likely culprit if modification is detected 337 * when the object is reallocated. 338 */ 339 copysize = size < MAX_COPY ? size : MAX_COPY; 340 end = (long *)&((caddr_t)addr)[copysize]; 341 for (lp = (long *)addr; lp < end; lp++) 342 *lp = WEIRD_ADDR; 343 freep->type = type; 344 #endif /* DIAGNOSTIC */ 345 #ifdef KMEMSTATS 346 kup->ku_freecnt++; 347 if (kup->ku_freecnt >= kbp->kb_elmpercl) 348 if (kup->ku_freecnt > kbp->kb_elmpercl) 349 panic("free: multiple frees"); 350 else if (kbp->kb_totalfree > kbp->kb_highwat) 351 kbp->kb_couldfree++; 352 kbp->kb_totalfree++; 353 ksp->ks_memuse -= size; 354 if (ksp->ks_memuse + size >= ksp->ks_limit && 355 ksp->ks_memuse < ksp->ks_limit) 356 wakeup((caddr_t)ksp); 357 ksp->ks_inuse--; 358 #endif 359 #ifdef OLD_MALLOC_MEMORY_POLICY 360 if (kbp->kb_next == NULL) 361 kbp->kb_next = addr; 362 else 363 ((struct freelist *)kbp->kb_last)->next = addr; 364 freep->next = NULL; 365 kbp->kb_last = addr; 366 #else 367 /* 368 * Return memory to the head of the queue for quick reuse. This 369 * can improve performance by improving the probability of the 370 * item being in the cache when it is reused. 371 */ 372 if (kbp->kb_next == NULL) { 373 kbp->kb_next = addr; 374 kbp->kb_last = addr; 375 freep->next = NULL; 376 } else { 377 freep->next = kbp->kb_next; 378 kbp->kb_next = addr; 379 } 380 #endif 381 splx(s); 382 } 383 384 /* 385 * Initialize the kernel memory allocator 386 */ 387 /* ARGSUSED*/ 388 static void 389 kmeminit(dummy) 390 void *dummy; 391 { 392 register long indx; 393 int npg; 394 395 #if ((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0) 396 #error "kmeminit: MAXALLOCSAVE not power of 2" 397 #endif 398 #if (MAXALLOCSAVE > MINALLOCSIZE * 32768) 399 #error "kmeminit: MAXALLOCSAVE too big" 400 #endif 401 #if (MAXALLOCSAVE < PAGE_SIZE) 402 #error "kmeminit: MAXALLOCSAVE too small" 403 #endif 404 npg = (nmbufs * MSIZE + nmbclusters * MCLBYTES + VM_KMEM_SIZE) 405 / PAGE_SIZE; 406 407 kmemusage = (struct kmemusage *) kmem_alloc(kernel_map, 408 (vm_size_t)(npg * sizeof(struct kmemusage))); 409 kmem_map = kmem_suballoc(kernel_map, (vm_offset_t *)&kmembase, 410 (vm_offset_t *)&kmemlimit, (vm_size_t)(npg * PAGE_SIZE), 411 FALSE); 412 #ifdef KMEMSTATS 413 for (indx = 0; indx < MINBUCKET + 16; indx++) { 414 if (1 << indx >= PAGE_SIZE) 415 bucket[indx].kb_elmpercl = 1; 416 else 417 bucket[indx].kb_elmpercl = PAGE_SIZE / (1 << indx); 418 bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl; 419 } 420 /* 421 * Limit maximum memory for each type to 60% of malloc area size or 422 * 60% of physical memory, whichever is smaller. 423 */ 424 for (indx = 0; indx < M_LAST; indx++) { 425 kmemstats[indx].ks_limit = min(cnt.v_page_count * PAGE_SIZE, 426 (npg * PAGE_SIZE - nmbclusters * MCLBYTES 427 - nmbufs * MSIZE)) * 6 / 10; 428 } 429 #endif 430 } 431