diff options
-rw-r--r-- | sys/kern/kern_malloc.c | 30 | ||||
-rw-r--r-- | sys/sys/malloc.h | 2 | ||||
-rw-r--r-- | sys/vm/memguard.c | 90 | ||||
-rw-r--r-- | sys/vm/memguard.h | 3 |
4 files changed, 112 insertions, 13 deletions
diff --git a/sys/kern/kern_malloc.c b/sys/kern/kern_malloc.c index 4864277..6b2e73d 100644 --- a/sys/kern/kern_malloc.c +++ b/sys/kern/kern_malloc.c @@ -142,12 +142,6 @@ struct { static uma_zone_t mt_zone; -#ifdef DEBUG_MEMGUARD -u_int vm_memguard_divisor; -SYSCTL_UINT(_vm, OID_AUTO, memguard_divisor, CTLFLAG_RD, &vm_memguard_divisor, - 0, "(kmem_size/memguard_divisor) == memguard submap size"); -#endif - u_int vm_kmem_size; SYSCTL_UINT(_vm, OID_AUTO, kmem_size, CTLFLAG_RD, &vm_kmem_size, 0, "Size of kernel memory"); @@ -304,8 +298,7 @@ malloc(unsigned long size, struct malloc_type *mtp, int flags) ("malloc(M_WAITOK) in interrupt context")); #ifdef DEBUG_MEMGUARD - /* XXX CHANGEME! */ - if (mtp == M_SUBPROC) + if (memguard_cmp(mtp)) return memguard_alloc(size, flags); #endif @@ -359,8 +352,7 @@ free(void *addr, struct malloc_type *mtp) return; #ifdef DEBUG_MEMGUARD - /* XXX CHANGEME! */ - if (mtp == M_SUBPROC) { + if (memguard_cmp(mtp)) { memguard_free(addr); return; } @@ -423,8 +415,7 @@ realloc(void *addr, unsigned long size, struct malloc_type *mtp, int flags) */ #ifdef DEBUG_MEMGUARD -/* XXX: CHANGEME! */ -if (mtp == M_SUBPROC) { +if (memguard_cmp(mtp)) { slab = NULL; alloc = size; } else { @@ -549,7 +540,7 @@ kmeminit(void *dummy) * scenarios as they occur. It is only used for debugging. */ vm_memguard_divisor = 10; - TUNABLE_INT_FETCH("vm.memguard_divisor", &vm_memguard_divisor); + TUNABLE_INT_FETCH("vm.memguard.divisor", &vm_memguard_divisor); /* Pick a conservative value if provided value sucks. */ if ((vm_memguard_divisor <= 0) || @@ -649,6 +640,19 @@ malloc_uninit(void *data) uma_zfree(mt_zone, mtip); } +struct malloc_type * +malloc_desc2type(const char *desc) +{ + struct malloc_type *mtp; + + mtx_assert(&malloc_mtx, MA_OWNED); + for (mtp = kmemstatistics; mtp != NULL; mtp = mtp->ks_next) { + if (strcmp(mtp->ks_shortdesc, desc) == 0) + return (mtp); + } + return (NULL); +} + static int sysctl_kern_malloc(SYSCTL_HANDLER_ARGS) { diff --git a/sys/sys/malloc.h b/sys/sys/malloc.h index f1bdedb..e59b9ac 100644 --- a/sys/sys/malloc.h +++ b/sys/sys/malloc.h @@ -189,6 +189,8 @@ void *realloc(void *addr, unsigned long size, struct malloc_type *type, int flags); void *reallocf(void *addr, unsigned long size, struct malloc_type *type, int flags); + +struct malloc_type *malloc_desc2type(const char *desc); #endif /* _KERNEL */ #endif /* !_SYS_MALLOC_H_ */ diff --git a/sys/vm/memguard.c b/sys/vm/memguard.c index 2140a0b..9a4f98b 100644 --- a/sys/vm/memguard.c +++ b/sys/vm/memguard.c @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include <sys/lock.h> #include <sys/mutex.h> #include <sys/malloc.h> +#include <sys/sysctl.h> #include <vm/vm.h> #include <vm/vm_param.h> @@ -59,6 +60,67 @@ __FBSDID("$FreeBSD$"); */ #define MAX_PAGES_PER_ITEM 64 +SYSCTL_NODE(_vm, OID_AUTO, memguard, CTLFLAG_RW, NULL, "MemGuard data"); +/* + * The vm_memguard_divisor variable controls how much of kmem_map should be + * reserved for MemGuard. + */ +u_int vm_memguard_divisor; +SYSCTL_UINT(_vm_memguard, OID_AUTO, divisor, CTLFLAG_RD, &vm_memguard_divisor, + 0, "(kmem_size/memguard_divisor) == memguard submap size"); + +/* + * Short description (ks_shortdesc) of memory type to monitor. + */ +static char vm_memguard_desc[128] = ""; +static struct malloc_type *vm_memguard_mtype = NULL; +TUNABLE_STR("vm.memguard.desc", vm_memguard_desc, sizeof(vm_memguard_desc)); +static int +memguard_sysctl_desc(SYSCTL_HANDLER_ARGS) +{ + struct malloc_type_internal *mtip; + struct malloc_type_stats *mtsp; + struct malloc_type *mtp; + char desc[128]; + long bytes; + int error, i; + + strlcpy(desc, vm_memguard_desc, sizeof(desc)); + error = sysctl_handle_string(oidp, desc, sizeof(desc), req); + if (error != 0 || req->newptr == NULL) + return (error); + + /* + * We can change memory type when no memory has been allocated for it + * or when there is no such memory type yet (ie. it will be loaded with + * kernel module). + */ + bytes = 0; + mtx_lock(&malloc_mtx); + mtp = malloc_desc2type(desc); + if (mtp != NULL) { + mtip = mtp->ks_handle; + for (i = 0; i < MAXCPU; i++) { + mtsp = &mtip->mti_stats[i]; + bytes += mtsp->mts_memalloced; + bytes -= mtsp->mts_memfreed; + } + } + if (bytes > 0) + error = EBUSY; + else { + /* + * If mtp is NULL, it will be initialized in memguard_cmp(). + */ + vm_memguard_mtype = mtp; + strlcpy(vm_memguard_desc, desc, sizeof(vm_memguard_desc)); + } + mtx_unlock(&malloc_mtx); + return (error); +} +SYSCTL_PROC(_vm_memguard, OID_AUTO, desc, CTLTYPE_STRING | CTLFLAG_RW, 0, 0, + memguard_sysctl_desc, "A", "Short description of memory type to monitor"); + /* * Global MemGuard data. */ @@ -239,6 +301,34 @@ memguard_free(void *addr) MEMGUARD_CRIT_SECTION_EXIT; } +int +memguard_cmp(struct malloc_type *mtp) +{ + +#if 1 + /* + * The safest way of comparsion is to always compare short description + * string of memory type, but it is also the slowest way. + */ + return (strcmp(mtp->ks_shortdesc, vm_memguard_desc) == 0); +#else + /* + * If we compare pointers, there are two possible problems: + * 1. Memory type was unloaded and new memory type was allocated at the + * same address. + * 2. Memory type was unloaded and loaded again, but allocated at a + * different address. + */ + if (vm_memguard_mtype != NULL) + return (mtp == vm_memguard_mtype); + if (strcmp(mtp->ks_shortdesc, vm_memguard_desc) == 0) { + vm_memguard_mtype = mtp; + return (1); + } + return (0); +#endif +} + /* * Guard a page containing specified object (make it read-only so that * future writes to it fail). diff --git a/sys/vm/memguard.h b/sys/vm/memguard.h index 10ca96d..34d79cf 100644 --- a/sys/vm/memguard.h +++ b/sys/vm/memguard.h @@ -26,6 +26,9 @@ * $FreeBSD$ */ +extern u_int vm_memguard_divisor; + void memguard_init(vm_map_t parent_map, unsigned long size); void *memguard_alloc(unsigned long size, int flags); void memguard_free(void *addr); +int memguard_cmp(struct malloc_type *mtp); |