Home | History | Annotate | Line # | Download | only in kern
kern_malloc.c revision 1.138.8.1
      1 /*	$NetBSD: kern_malloc.c,v 1.138.8.1 2017/08/18 14:52:43 snj Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1987, 1991, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  *
     31  *	@(#)kern_malloc.c	8.4 (Berkeley) 5/20/95
     32  */
     33 
     34 /*
     35  * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
     36  *
     37  * Redistribution and use in source and binary forms, with or without
     38  * modification, are permitted provided that the following conditions
     39  * are met:
     40  * 1. Redistributions of source code must retain the above copyright
     41  *    notice, this list of conditions and the following disclaimer.
     42  * 2. Redistributions in binary form must reproduce the above copyright
     43  *    notice, this list of conditions and the following disclaimer in the
     44  *    documentation and/or other materials provided with the distribution.
     45  * 3. All advertising materials mentioning features or use of this software
     46  *    must display the following acknowledgement:
     47  *	This product includes software developed by the University of
     48  *	California, Berkeley and its contributors.
     49  * 4. Neither the name of the University nor the names of its contributors
     50  *    may be used to endorse or promote products derived from this software
     51  *    without specific prior written permission.
     52  *
     53  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     63  * SUCH DAMAGE.
     64  *
     65  *	@(#)kern_malloc.c	8.4 (Berkeley) 5/20/95
     66  */
     67 
     68 #include <sys/cdefs.h>
     69 __KERNEL_RCSID(0, "$NetBSD: kern_malloc.c,v 1.138.8.1 2017/08/18 14:52:43 snj Exp $");
     70 
     71 #include <sys/param.h>
     72 #include <sys/proc.h>
     73 #include <sys/kernel.h>
     74 #include <sys/malloc.h>
     75 #include <sys/kmem.h>
     76 #include <sys/systm.h>
     77 #include <sys/debug.h>
     78 #include <sys/mutex.h>
     79 #include <sys/lockdebug.h>
     80 
     81 #include <uvm/uvm_extern.h>
     82 
     83 #include "opt_kmemstats.h"
     84 #include "opt_malloclog.h"
     85 #include "opt_malloc_debug.h"
     86 
     87 struct kmembuckets kmembuckets[MINBUCKET + 16];
     88 struct kmemusage *kmemusage;
     89 struct malloc_type *kmemstatistics;
     90 
     91 kmutex_t malloc_lock;
     92 
     93 struct malloc_header {
     94 	/* Total size, include the header. */
     95 	size_t		mh_size;
     96 } __aligned(ALIGNBYTES+1);
     97 
     98 /*
     99  * Allocate a block of memory
    100  */
    101 #ifdef MALLOCLOG
    102 void *
    103 _kern_malloc(unsigned long size, struct malloc_type *ksp, int flags,
    104     const char *file, long line)
    105 #else
    106 void *
    107 kern_malloc(unsigned long size, struct malloc_type *ksp, int flags)
    108 #endif /* MALLOCLOG */
    109 {
    110 	const int kmflags = (flags & M_NOWAIT) ? KM_NOSLEEP : KM_SLEEP;
    111 	size_t allocsize, hdroffset;
    112 	struct malloc_header *mh;
    113 	void *p;
    114 
    115 	if (size >= PAGE_SIZE) {
    116 		if (size > (ULONG_MAX-PAGE_SIZE))
    117 			allocsize = ULONG_MAX;	/* this will fail later */
    118 		else
    119 			allocsize = PAGE_SIZE + size; /* for page alignment */
    120 		hdroffset = PAGE_SIZE - sizeof(struct malloc_header);
    121 	} else {
    122 		allocsize = sizeof(struct malloc_header) + size;
    123 		hdroffset = 0;
    124 	}
    125 
    126 	p = kmem_intr_alloc(allocsize, kmflags);
    127 	if (p == NULL)
    128 		return NULL;
    129 
    130 	if ((flags & M_ZERO) != 0) {
    131 		memset(p, 0, allocsize);
    132 	}
    133 	mh = (void *)((char *)p + hdroffset);
    134 	mh->mh_size = allocsize - hdroffset;
    135 
    136 	return mh + 1;
    137 }
    138 
    139 /*
    140  * Free a block of memory allocated by malloc.
    141  */
    142 #ifdef MALLOCLOG
    143 void
    144 _kern_free(void *addr, struct malloc_type *ksp, const char *file, long line)
    145 #else
    146 void
    147 kern_free(void *addr, struct malloc_type *ksp)
    148 #endif /* MALLOCLOG */
    149 {
    150 	struct malloc_header *mh;
    151 
    152 	mh = addr;
    153 	mh--;
    154 
    155 	if (mh->mh_size >= PAGE_SIZE + sizeof(struct malloc_header))
    156 		kmem_intr_free((char *)addr - PAGE_SIZE,
    157 		    mh->mh_size + PAGE_SIZE - sizeof(struct malloc_header));
    158 	else
    159 		kmem_intr_free(mh, mh->mh_size);
    160 }
    161 
    162 /*
    163  * Change the size of a block of memory.
    164  */
    165 void *
    166 kern_realloc(void *curaddr, unsigned long newsize, struct malloc_type *ksp,
    167     int flags)
    168 {
    169 	struct malloc_header *mh;
    170 	unsigned long cursize;
    171 	void *newaddr;
    172 
    173 	/*
    174 	 * realloc() with a NULL pointer is the same as malloc().
    175 	 */
    176 	if (curaddr == NULL)
    177 		return (malloc(newsize, ksp, flags));
    178 
    179 	/*
    180 	 * realloc() with zero size is the same as free().
    181 	 */
    182 	if (newsize == 0) {
    183 		free(curaddr, ksp);
    184 		return (NULL);
    185 	}
    186 
    187 #ifdef LOCKDEBUG
    188 	if ((flags & M_NOWAIT) == 0) {
    189 		ASSERT_SLEEPABLE();
    190 	}
    191 #endif
    192 
    193 	mh = curaddr;
    194 	mh--;
    195 
    196 	cursize = mh->mh_size - sizeof(struct malloc_header);
    197 
    198 	/*
    199 	 * If we already actually have as much as they want, we're done.
    200 	 */
    201 	if (newsize <= cursize)
    202 		return (curaddr);
    203 
    204 	/*
    205 	 * Can't satisfy the allocation with the existing block.
    206 	 * Allocate a new one and copy the data.
    207 	 */
    208 	newaddr = malloc(newsize, ksp, flags);
    209 	if (__predict_false(newaddr == NULL)) {
    210 		/*
    211 		 * malloc() failed, because flags included M_NOWAIT.
    212 		 * Return NULL to indicate that failure.  The old
    213 		 * pointer is still valid.
    214 		 */
    215 		return (NULL);
    216 	}
    217 	memcpy(newaddr, curaddr, cursize);
    218 
    219 	/*
    220 	 * We were successful: free the old allocation and return
    221 	 * the new one.
    222 	 */
    223 	free(curaddr, ksp);
    224 	return (newaddr);
    225 }
    226 
    227 /*
    228  * Add a malloc type to the system.
    229  */
    230 void
    231 malloc_type_attach(struct malloc_type *type)
    232 {
    233 
    234 	if (type->ks_magic != M_MAGIC)
    235 		panic("malloc_type_attach: bad magic");
    236 
    237 #ifdef DIAGNOSTIC
    238 	{
    239 		struct malloc_type *ksp;
    240 		for (ksp = kmemstatistics; ksp != NULL; ksp = ksp->ks_next) {
    241 			if (ksp == type)
    242 				panic("%s: `%s' already on list", __func__,
    243 				    type->ks_shortdesc);
    244 		}
    245 	}
    246 #endif
    247 
    248 #ifdef KMEMSTATS
    249 #else
    250 	type->ks_limit = 0;
    251 #endif
    252 
    253 	type->ks_next = kmemstatistics;
    254 	kmemstatistics = type;
    255 }
    256 
    257 /*
    258  * Remove a malloc type from the system..
    259  */
    260 void
    261 malloc_type_detach(struct malloc_type *type)
    262 {
    263 	struct malloc_type *ksp;
    264 
    265 #ifdef DIAGNOSTIC
    266 	if (type->ks_magic != M_MAGIC)
    267 		panic("malloc_type_detach: bad magic");
    268 #endif
    269 
    270 	if (type == kmemstatistics)
    271 		kmemstatistics = type->ks_next;
    272 	else {
    273 		for (ksp = kmemstatistics; ksp->ks_next != NULL;
    274 		     ksp = ksp->ks_next) {
    275 			if (ksp->ks_next == type) {
    276 				ksp->ks_next = type->ks_next;
    277 				break;
    278 			}
    279 		}
    280 #ifdef DIAGNOSTIC
    281 		if (ksp->ks_next == NULL)
    282 			panic("malloc_type_detach: not on list");
    283 #endif
    284 	}
    285 	type->ks_next = NULL;
    286 }
    287 
    288 /*
    289  * Set the limit on a malloc type.
    290  */
    291 void
    292 malloc_type_setlimit(struct malloc_type *type, u_long limit)
    293 {
    294 #ifdef KMEMSTATS
    295 	mutex_spin_enter(&malloc_lock);
    296 	type->ks_limit = limit;
    297 	mutex_spin_exit(&malloc_lock);
    298 #endif
    299 }
    300 
    301 /*
    302  * Initialize the kernel memory allocator
    303  */
    304 void
    305 kmeminit(void)
    306 {
    307 	__link_set_decl(malloc_types, struct malloc_type);
    308 	struct malloc_type * const *ksp;
    309 #ifdef KMEMSTATS
    310 	long indx;
    311 #endif
    312 
    313 	mutex_init(&malloc_lock, MUTEX_DEFAULT, IPL_VM);
    314 
    315 #ifdef KMEMSTATS
    316 	for (indx = 0; indx < MINBUCKET + 16; indx++) {
    317 		if (1 << indx >= PAGE_SIZE)
    318 			kmembuckets[indx].kb_elmpercl = 1;
    319 		else
    320 			kmembuckets[indx].kb_elmpercl = PAGE_SIZE / (1 << indx);
    321 		kmembuckets[indx].kb_highwat =
    322 			5 * kmembuckets[indx].kb_elmpercl;
    323 	}
    324 #endif
    325 
    326 	/* Attach all of the statically-linked malloc types. */
    327 	__link_set_foreach(ksp, malloc_types)
    328 		malloc_type_attach(*ksp);
    329 
    330 #ifdef MALLOC_DEBUG
    331 	debug_malloc_init();
    332 #endif
    333 }
    334 
    335 #ifdef DDB
    336 #include <ddb/db_output.h>
    337 
    338 /*
    339  * Dump kmem statistics from ddb.
    340  *
    341  * usage: call dump_kmemstats
    342  */
    343 void	dump_kmemstats(void);
    344 
    345 void
    346 dump_kmemstats(void)
    347 {
    348 #ifdef KMEMSTATS
    349 	struct malloc_type *ksp;
    350 
    351 	for (ksp = kmemstatistics; ksp != NULL; ksp = ksp->ks_next) {
    352 		if (ksp->ks_memuse == 0)
    353 			continue;
    354 		db_printf("%s%.*s %ld\n", ksp->ks_shortdesc,
    355 		    (int)(20 - strlen(ksp->ks_shortdesc)),
    356 		    "                    ",
    357 		    ksp->ks_memuse);
    358 	}
    359 #else
    360 	db_printf("Kmem stats are not being collected.\n");
    361 #endif /* KMEMSTATS */
    362 }
    363 #endif /* DDB */
    364 
    365 
    366 #if 0
    367 /*
    368  * Diagnostic messages about "Data modified on
    369  * freelist" indicate a memory corruption, but
    370  * they do not help tracking it down.
    371  * This function can be called at various places
    372  * to sanity check malloc's freelist and discover
    373  * where does the corruption take place.
    374  */
    375 int
    376 freelist_sanitycheck(void) {
    377 	int i,j;
    378 	struct kmembuckets *kbp;
    379 	struct freelist *freep;
    380 	int rv = 0;
    381 
    382 	for (i = MINBUCKET; i <= MINBUCKET + 15; i++) {
    383 		kbp = &kmembuckets[i];
    384 		freep = (struct freelist *)kbp->kb_next;
    385 		j = 0;
    386 		while(freep) {
    387 			vm_map_lock(kmem_map);
    388 			rv = uvm_map_checkprot(kmem_map, (vaddr_t)freep,
    389 			    (vaddr_t)freep + sizeof(struct freelist),
    390 			    VM_PROT_WRITE);
    391 			vm_map_unlock(kmem_map);
    392 
    393 			if ((rv == 0) || (*(int *)freep != WEIRD_ADDR)) {
    394 				printf("bucket %i, chunck %d at %p modified\n",
    395 				    i, j, freep);
    396 				return 1;
    397 			}
    398 			freep = (struct freelist *)freep->next;
    399 			j++;
    400 		}
    401 	}
    402 
    403 	return 0;
    404 }
    405 #endif
    406