/*
- * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
- *
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License"). You may not use this file except in compliance with the
- * License. Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
- *
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/* Copyright (c) 1995, 1997 Apple Computer, Inc. All Rights Reserved */
/*
*
* @(#)kern_malloc.c 8.4 (Berkeley) 5/20/95
*/
+/*
+ * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
+ * support for mandatory and extensible security protections. This notice
+ * is included in support of clause 2.2 (b) of the Apple Public License,
+ * Version 2.0.
+ */
+
+#include <kern/zalloc.h>
+#include <kern/kalloc.h>
-#include <sys/param.h>
#include <sys/malloc.h>
+#include <sys/sysctl.h>
-#include <sys/socket.h>
-#include <sys/socketvar.h>
+#include <libkern/libkern.h>
-#include <net/route.h>
+ZONE_VIEW_DEFINE(ZV_NAMEI, "vfs.namei", KHEAP_ID_DATA_BUFFERS, MAXPATHLEN);
-#include <netinet/in.h>
-#include <netinet/in_systm.h>
-#include <netinet/ip.h>
-#include <netinet/in_pcb.h>
+static void *
+__MALLOC_ext(
+ size_t size,
+ int type,
+ int flags,
+ vm_allocation_site_t *site,
+ kalloc_heap_t heap)
+{
+ void *addr = NULL;
-#include <sys/event.h>
-#include <sys/eventvar.h>
+ if (type >= M_LAST) {
+ panic("_malloc TYPE");
+ }
-#include <sys/proc_internal.h>
-#include <sys/mount_internal.h>
-#include <sys/vnode_internal.h>
-#include <sys/ubc_internal.h>
-#include <sys/namei.h>
-#include <sys/file_internal.h>
-#include <sys/filedesc.h>
-#include <sys/tty.h>
-#include <sys/quota.h>
-#include <sys/uio_internal.h>
+ if (size == 0) {
+ return NULL;
+ }
-#include <ufs/ufs/inode.h>
+ static_assert(sizeof(vm_size_t) == sizeof(size_t));
+ static_assert(M_WAITOK == Z_WAITOK);
+ static_assert(M_NOWAIT == Z_NOWAIT);
+ static_assert(M_ZERO == Z_ZERO);
-#include <hfs/hfs_cnode.h>
-#include <isofs/cd9660/cd9660_node.h>
+ addr = kalloc_ext(heap, size,
+ flags & (M_WAITOK | M_NOWAIT | M_ZERO), site).addr;
+ if (__probable(addr)) {
+ return addr;
+ }
-#include <miscfs/volfs/volfs.h>
-#include <miscfs/specfs/specdev.h>
+ if (flags & (M_NOWAIT | M_NULL)) {
+ return NULL;
+ }
-#include <nfs/rpcv2.h>
-#include <nfs/nfsproto.h>
-#include <nfs/nfsnode.h>
-#include <nfs/nfsmount.h>
+ /*
+ * We get here when the caller told us to block waiting for memory, but
+ * kalloc said there's no memory left to get. Generally, this means there's a
+ * leak or the caller asked for an impossibly large amount of memory. If the caller
+ * is expecting a NULL return code then it should explicitly set the flag M_NULL.
+ * If the caller isn't expecting a NULL return code, we just panic. This is less
+ * than ideal, but returning NULL when the caller isn't expecting it doesn't help
+ * since the majority of callers don't check the return value and will just
+ * dereference the pointer and trap anyway. We may as well get a more
+ * descriptive message out while we can.
+ */
+ panic("_MALLOC: kalloc returned NULL (potential leak), size %llu", (uint64_t) size);
+}
-#include <vfs/vfs_journal.h>
+void *
+__MALLOC(size_t size, int type, int flags, vm_allocation_site_t *site)
+{
+ return __MALLOC_ext(size, type, flags, site, KHEAP_DEFAULT);
+}
-#include <mach/mach_types.h>
+void *
+__REALLOC(
+ void *addr,
+ size_t size,
+ int type __unused,
+ int flags,
+ vm_allocation_site_t *site)
+{
+ addr = kheap_realloc_addr(KHEAP_DEFAULT, addr, size,
+ flags & (M_WAITOK | M_NOWAIT | M_ZERO), site).addr;
-#include <kern/zalloc.h>
-#include <kern/kalloc.h>
+ if (__probable(addr)) {
+ return addr;
+ }
-struct kmemstats kmemstats[M_LAST];
-char *memname[] = INITKMEMNAMES;
-
-struct kmzones {
- size_t kz_elemsize;
- void *kz_zalloczone;
-#define KMZ_CREATEZONE ((void *)-2)
-#define KMZ_LOOKUPZONE ((void *)-1)
-#define KMZ_MALLOC ((void *)0)
-#define KMZ_SHAREZONE ((void *)1)
-} kmzones[M_LAST] = {
-#define SOS(sname) sizeof (struct sname)
-#define SOX(sname) -1
- -1, 0, /* 0 M_FREE */
- MSIZE, KMZ_CREATEZONE, /* 1 M_MBUF */
- 0, KMZ_MALLOC, /* 2 M_DEVBUF */
- SOS(socket), KMZ_CREATEZONE, /* 3 M_SOCKET */
- SOS(inpcb), KMZ_LOOKUPZONE, /* 4 M_PCB */
- M_MBUF, KMZ_SHAREZONE, /* 5 M_RTABLE */
- M_MBUF, KMZ_SHAREZONE, /* 6 M_HTABLE */
- M_MBUF, KMZ_SHAREZONE, /* 7 M_FTABLE */
- SOS(rusage), KMZ_CREATEZONE, /* 8 M_ZOMBIE */
- 0, KMZ_MALLOC, /* 9 M_IFADDR */
- M_MBUF, KMZ_SHAREZONE, /* 10 M_SOOPTS */
- 0, KMZ_MALLOC, /* 11 M_SONAME */
- MAXPATHLEN, KMZ_CREATEZONE, /* 12 M_NAMEI */
- 0, KMZ_MALLOC, /* 13 M_GPROF */
- 0, KMZ_MALLOC, /* 14 M_IOCTLOPS */
- 0, KMZ_MALLOC, /* 15 M_MAPMEM */
- SOS(ucred), KMZ_CREATEZONE, /* 16 M_CRED */
- SOS(pgrp), KMZ_CREATEZONE, /* 17 M_PGRP */
- SOS(session), KMZ_CREATEZONE, /* 18 M_SESSION */
- SOS(iovec_32), KMZ_LOOKUPZONE, /* 19 M_IOV32 */
- SOS(mount), KMZ_CREATEZONE, /* 20 M_MOUNT */
- 0, KMZ_MALLOC, /* 21 M_FHANDLE */
- SOS(nfsreq), KMZ_CREATEZONE, /* 22 M_NFSREQ */
- SOS(nfsmount), KMZ_CREATEZONE, /* 23 M_NFSMNT */
- SOS(nfsnode), KMZ_CREATEZONE, /* 24 M_NFSNODE */
- SOS(vnode), KMZ_CREATEZONE, /* 25 M_VNODE */
- SOS(namecache), KMZ_CREATEZONE, /* 26 M_CACHE */
- SOX(dquot), KMZ_LOOKUPZONE, /* 27 M_DQUOT */
- SOX(ufsmount), KMZ_LOOKUPZONE, /* 28 M_UFSMNT */
- 0, KMZ_MALLOC, /* 29 M_CGSUM */
- 0, KMZ_MALLOC, /* 30 M_VMMAP */
- 0, KMZ_MALLOC, /* 31 M_VMMAPENT */
- 0, KMZ_MALLOC, /* 32 M_VMOBJ */
- 0, KMZ_MALLOC, /* 33 M_VMOBJHASH */
- 0, KMZ_MALLOC, /* 34 M_VMPMAP */
- 0, KMZ_MALLOC, /* 35 M_VMPVENT */
- 0, KMZ_MALLOC, /* 36 M_VMPAGER */
- 0, KMZ_MALLOC, /* 37 M_VMPGDATA */
- SOS(fileproc), KMZ_CREATEZONE, /* 38 M_FILEPROC */
- SOS(filedesc), KMZ_CREATEZONE, /* 39 M_FILEDESC */
- SOX(lockf), KMZ_CREATEZONE, /* 40 M_LOCKF */
- SOS(proc), KMZ_CREATEZONE, /* 41 M_PROC */
- SOS(pstats), KMZ_CREATEZONE, /* 42 M_SUBPROC */
- 0, KMZ_MALLOC, /* 43 M_SEGMENT */
- M_FFSNODE, KMZ_SHAREZONE, /* 44 M_LFSNODE */
- SOS(inode), KMZ_CREATEZONE, /* 45 M_FFSNODE */
- M_FFSNODE, KMZ_SHAREZONE, /* 46 M_MFSNODE */
- 0, KMZ_MALLOC, /* 47 M_NQLEASE */
- 0, KMZ_MALLOC, /* 48 M_NQMHOST */
- 0, KMZ_MALLOC, /* 49 M_NETADDR */
- SOX(nfssvc_sock),
- KMZ_CREATEZONE, /* 50 M_NFSSVC */
- SOS(nfsuid), KMZ_CREATEZONE, /* 51 M_NFSUID */
- SOX(nfsrvcache),
- KMZ_CREATEZONE, /* 52 M_NFSD */
- SOX(ip_moptions),
- KMZ_LOOKUPZONE, /* 53 M_IPMOPTS */
- SOX(in_multi), KMZ_LOOKUPZONE, /* 54 M_IPMADDR */
- SOX(ether_multi),
- KMZ_LOOKUPZONE, /* 55 M_IFMADDR */
- SOX(mrt), KMZ_CREATEZONE, /* 56 M_MRTABLE */
- SOX(iso_mnt), KMZ_LOOKUPZONE, /* 57 M_ISOFSMNT */
- SOS(iso_node), KMZ_CREATEZONE, /* 58 M_ISOFSNODE */
- SOS(nfsrv_descript),
- KMZ_CREATEZONE, /* 59 M_NFSRVDESC */
- SOS(nfsdmap), KMZ_CREATEZONE, /* 60 M_NFSDIROFF */
- SOS(fhandle), KMZ_LOOKUPZONE, /* 61 M_NFSBIGFH */
- 0, KMZ_MALLOC, /* 62 M_MSDOSFSMNT */
- 0, KMZ_MALLOC, /* 63 M_MSDOSFSFAT */
- 0, KMZ_MALLOC, /* 64 M_MSDOSFSNODE */
- SOS(tty), KMZ_CREATEZONE, /* 65 M_TTYS */
- 0, KMZ_MALLOC, /* 66 M_EXEC */
- 0, KMZ_MALLOC, /* 67 M_MISCFSMNT */
- 0, KMZ_MALLOC, /* 68 M_MISCFSNODE */
- 0, KMZ_MALLOC, /* 69 M_ADOSFSMNT */
- 0, KMZ_MALLOC, /* 70 M_ADOSFSNODE */
- 0, KMZ_MALLOC, /* 71 M_ANODE */
- SOX(buf), KMZ_CREATEZONE, /* 72 M_BUFHDR */
- (NDFILE * OFILESIZE),
- KMZ_CREATEZONE, /* 73 M_OFILETABL */
- MCLBYTES, KMZ_CREATEZONE, /* 74 M_MCLUST */
- SOX(hfsmount), KMZ_LOOKUPZONE, /* 75 M_HFSMNT */
- SOS(cnode), KMZ_CREATEZONE, /* 76 M_HFSNODE */
- SOS(filefork), KMZ_CREATEZONE, /* 77 M_HFSFORK */
- SOX(volfs_mntdata), KMZ_LOOKUPZONE, /* 78 M_VOLFSMNT */
- SOS(volfs_vndata), KMZ_CREATEZONE, /* 79 M_VOLFSNODE */
- 0, KMZ_MALLOC, /* 80 M_TEMP */
- 0, KMZ_MALLOC, /* 81 M_SECA */
- 0, KMZ_MALLOC, /* 82 M_DEVFS */
- 0, KMZ_MALLOC, /* 83 M_IPFW */
- 0, KMZ_MALLOC, /* 84 M_UDFNODE */
- 0, KMZ_MALLOC, /* 85 M_UDFMOUNT */
- 0, KMZ_MALLOC, /* 86 M_IP6NDP */
- 0, KMZ_MALLOC, /* 87 M_IP6OPT */
- 0, KMZ_MALLOC, /* 88 M_IP6MISC */
- 0, KMZ_MALLOC, /* 89 M_TSEGQ */
- 0, KMZ_MALLOC, /* 90 M_IGMP */
- SOS(journal), KMZ_CREATEZONE, /* 91 M_JNL_JNL */
- SOS(transaction), KMZ_CREATEZONE, /* 92 M_JNL_TR */
- SOS(specinfo), KMZ_CREATEZONE, /* 93 M_SPECINFO */
- SOS(kqueue), KMZ_CREATEZONE, /* 94 M_KQUEUE */
- SOS(directoryhint), KMZ_CREATEZONE, /* 95 M_HFSDIRHINT */
- SOS(cl_readahead), KMZ_CREATEZONE, /* 96 M_CLRDAHEAD */
- SOS(cl_writebehind),KMZ_CREATEZONE, /* 97 M_CLWRBEHIND */
- SOS(iovec_64), KMZ_LOOKUPZONE, /* 98 M_IOV64 */
- SOS(fileglob), KMZ_CREATEZONE, /* 99 M_FILEGLOB */
- 0, KMZ_MALLOC, /* 100 M_KAUTH */
- 0, KMZ_MALLOC, /* 101 M_DUMMYNET */
- SOS(unsafe_fsnode),KMZ_CREATEZONE, /* 102 M_UNSAFEFS */
-#undef SOS
-#undef SOX
-};
-
-extern zone_t kalloc_zone(vm_size_t); /* XXX */
+ if (flags & (M_NOWAIT | M_NULL)) {
+ return NULL;
+ }
+
+ panic("_REALLOC: kalloc returned NULL (potential leak), size %llu", (uint64_t) size);
+}
+
+void *
+_MALLOC_external(size_t size, int type, int flags);
+void *
+_MALLOC_external(size_t size, int type, int flags)
+{
+ static vm_allocation_site_t site = {
+ .tag = VM_KERN_MEMORY_KALLOC,
+ .flags = VM_TAG_BT,
+ };
+ return __MALLOC_ext(size, type, flags, &site, KHEAP_KEXT);
+}
-/*
- * Initialize the kernel memory allocator
- */
void
-kmeminit(void)
+_FREE_external(void *addr, int type);
+void
+_FREE_external(void *addr, int type __unused)
{
- struct kmzones *kmz;
+ /*
+ * hashinit and other functions allocate on behalf of kexts and do not have
+ * a matching hashdestroy, so we sadly have to allow this for now.
+ */
+ kheap_free_addr(KHEAP_ANY, addr);
+}
- if ((sizeof(kmzones)/sizeof(kmzones[0])) != (sizeof(memname)/sizeof(memname[0]))) {
- panic("kmeminit: kmzones has %d elements but memname has %d\n",
- (sizeof(kmzones)/sizeof(kmzones[0])), (sizeof(memname)/sizeof(memname[0])));
- }
+void
+_FREE_ZONE_external(void *elem, size_t size, int type);
+void
+_FREE_ZONE_external(void *elem, size_t size, int type __unused)
+{
+ (kheap_free)(KHEAP_KEXT, elem, size);
+}
- kmz = kmzones;
- while (kmz < &kmzones[M_LAST]) {
-/* XXX */
- if (kmz->kz_elemsize == -1)
- ;
- else
-/* XXX */
- if (kmz->kz_zalloczone == KMZ_CREATEZONE) {
- kmz->kz_zalloczone = zinit(kmz->kz_elemsize,
- 1024 * 1024, PAGE_SIZE,
- memname[kmz - kmzones]);
- }
- else if (kmz->kz_zalloczone == KMZ_LOOKUPZONE)
- kmz->kz_zalloczone = kalloc_zone(kmz->kz_elemsize);
+#if DEBUG || DEVELOPMENT
- kmz++;
- }
+extern unsigned int zone_map_jetsam_limit;
- kmz = kmzones;
- while (kmz < &kmzones[M_LAST]) {
-/* XXX */
- if (kmz->kz_elemsize == -1)
- ;
- else
-/* XXX */
- if (kmz->kz_zalloczone == KMZ_SHAREZONE) {
- kmz->kz_zalloczone =
- kmzones[kmz->kz_elemsize].kz_zalloczone;
- kmz->kz_elemsize =
- kmzones[kmz->kz_elemsize].kz_elemsize;
- }
+static int
+sysctl_zone_map_jetsam_limit SYSCTL_HANDLER_ARGS
+{
+#pragma unused(oidp, arg1, arg2)
+ int oldval = 0, val = 0, error = 0;
+
+ oldval = zone_map_jetsam_limit;
+ error = sysctl_io_number(req, oldval, sizeof(int), &val, NULL);
+ if (error || !req->newptr) {
+ return error;
+ }
- kmz++;
+ if (val <= 0 || val > 100) {
+ printf("sysctl_zone_map_jetsam_limit: new jetsam limit value is invalid.\n");
+ return EINVAL;
}
+
+ zone_map_jetsam_limit = val;
+ return 0;
}
-#define MDECL(reqlen) \
-union { \
- struct _mhead hdr; \
- char _m[(reqlen) + sizeof (struct _mhead)]; \
+SYSCTL_PROC(_kern, OID_AUTO, zone_map_jetsam_limit, CTLTYPE_INT | CTLFLAG_RW, 0, 0,
+ sysctl_zone_map_jetsam_limit, "I", "Zone map jetsam limit");
+
+
+extern void get_zone_map_size(uint64_t *current_size, uint64_t *capacity);
+
+static int
+sysctl_zone_map_size_and_capacity SYSCTL_HANDLER_ARGS
+{
+#pragma unused(oidp, arg1, arg2)
+ uint64_t zstats[2];
+ get_zone_map_size(&zstats[0], &zstats[1]);
+
+ return SYSCTL_OUT(req, &zstats, sizeof(zstats));
}
-struct _mhead {
- size_t mlen;
- char dat[0];
-};
+SYSCTL_PROC(_kern, OID_AUTO, zone_map_size_and_capacity,
+ CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_MASKED | CTLFLAG_LOCKED,
+ 0, 0, &sysctl_zone_map_size_and_capacity, "Q", "Current size and capacity of the zone map");
-#define ZEROSIZETOKEN (void *)0xFADEDFAD
-void *
-_MALLOC(
- size_t size,
- int type,
- int flags)
+extern boolean_t run_zone_test(void);
+
+static int
+sysctl_run_zone_test SYSCTL_HANDLER_ARGS
{
- MDECL(size) *mem;
- size_t memsize = sizeof (*mem);
+#pragma unused(oidp, arg1, arg2)
+ /* require setting this sysctl to prevent sysctl -a from running this */
+ if (!req->newptr) {
+ return 0;
+ }
- if (type >= M_LAST)
- panic("_malloc TYPE");
+ int ret_val = run_zone_test();
+ return SYSCTL_OUT(req, &ret_val, sizeof(ret_val));
+}
+
+SYSCTL_PROC(_kern, OID_AUTO, run_zone_test,
+ CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_MASKED | CTLFLAG_LOCKED,
+ 0, 0, &sysctl_run_zone_test, "I", "Test zone allocator KPI");
+
+#endif /* DEBUG || DEVELOPMENT */
+
+#if CONFIG_ZLEAKS
+SYSCTL_DECL(_kern_zleak);
+SYSCTL_NODE(_kern, OID_AUTO, zleak, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "zleak");
+
+/*
+ * kern.zleak.active
+ *
+ * Show the status of the zleak subsystem (0 = enabled, 1 = active,
+ * and -1 = failed), and if enabled, allow it to be activated immediately.
+ */
+static int
+sysctl_zleak_active SYSCTL_HANDLER_ARGS
+{
+#pragma unused(arg1, arg2)
+ int oldval, val, error;
+
+ val = oldval = get_zleak_state();
+ error = sysctl_handle_int(oidp, &val, 0, req);
+ if (error || !req->newptr) {
+ return error;
+ }
/*
- * On zero request we do not return zero as that
- * could be mistaken for ENOMEM.
+ * Can only be activated if it's off (and not failed.)
+ * Cannot be deactivated once it's on.
*/
- if (size == 0)
- return (ZEROSIZETOKEN);
+ if (val == 1 && oldval == 0) {
+ kern_return_t kr = zleak_activate();
- if (flags & M_NOWAIT) {
- mem = (void *)kalloc_noblock(memsize);
- } else {
- mem = (void *)kalloc(memsize);
+ if (KERN_SUCCESS != kr) {
+ printf("zleak_active: failed to activate "
+ "live zone leak debugging (%d).\n", kr);
+ }
+ }
+ if (val == 0 && oldval == 1) {
+ printf("zleak_active: active, cannot be disabled.\n");
+ return EINVAL;
}
- if (!mem)
- return (0);
+ return 0;
+}
- mem->hdr.mlen = memsize;
+SYSCTL_PROC(_kern_zleak, OID_AUTO, active,
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
+ 0, 0, sysctl_zleak_active, "I", "zleak activity");
- if (flags & M_ZERO)
- bzero(mem->hdr.dat, size);
+/*
+ * kern.zleak.max_zonemap_size
+ *
+ * Read the value of the maximum zonemap size in bytes; useful
+ * as the maximum size that zleak.global_threshold and
+ * zleak.zone_threshold should be set to.
+ */
+static int
+sysctl_zleak_max_zonemap_size SYSCTL_HANDLER_ARGS
+{
+ uint64_t zmap_max_size = *(vm_size_t *)arg1;
- return (mem->hdr.dat);
+ return sysctl_handle_quad(oidp, &zmap_max_size, arg2, req);
}
-void
-_FREE(
- void *addr,
- int type)
+SYSCTL_PROC(_kern_zleak, OID_AUTO, max_zonemap_size,
+ CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_LOCKED,
+ &zleak_max_zonemap_size, 0,
+ sysctl_zleak_max_zonemap_size, "Q", "zleak max zonemap size");
+
+
+static int
+sysctl_zleak_threshold SYSCTL_HANDLER_ARGS
{
- struct _mhead *hdr;
+#pragma unused(oidp, arg2)
+ int error;
+ uint64_t value = *(vm_size_t *)arg1;
- if (type >= M_LAST)
- panic("_free TYPE");
+ error = sysctl_io_number(req, value, sizeof(value), &value, NULL);
- if (addr == (void *)ZEROSIZETOKEN)
- return;
- if (!addr)
- return; /* correct (convenient bsd kernel legacy) */
+ if (error || !req->newptr) {
+ return error;
+ }
- hdr = addr; hdr--;
- kfree(hdr, hdr->mlen);
+ if (value > (uint64_t)zleak_max_zonemap_size) {
+ return ERANGE;
+ }
+
+ *(vm_size_t *)arg1 = value;
+ return 0;
}
-void *
-_MALLOC_ZONE(
- size_t size,
- int type,
- int flags)
+/*
+ * kern.zleak.global_threshold
+ *
+ * Set the global zleak threshold size (in bytes). If the zone map
+ * grows larger than this value, zleaks are automatically activated.
+ *
+ * The default value is set in zleak_init().
+ */
+SYSCTL_PROC(_kern_zleak, OID_AUTO, global_threshold,
+ CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED,
+ &zleak_global_tracking_threshold, 0,
+ sysctl_zleak_threshold, "Q", "zleak global threshold");
+
+/*
+ * kern.zleak.zone_threshold
+ *
+ * Set the per-zone threshold size (in bytes) above which any
+ * zone will automatically start zleak tracking.
+ *
+ * The default value is set in zleak_init().
+ *
+ * Setting this variable will have no effect until zleak tracking is
+ * activated (See above.)
+ */
+SYSCTL_PROC(_kern_zleak, OID_AUTO, zone_threshold,
+ CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED,
+ &zleak_per_zone_tracking_threshold, 0,
+ sysctl_zleak_threshold, "Q", "zleak per-zone threshold");
+
+#endif /* CONFIG_ZLEAKS */
+
+extern uint64_t get_zones_collectable_bytes(void);
+
+static int
+sysctl_zones_collectable_bytes SYSCTL_HANDLER_ARGS
{
- struct kmzones *kmz;
- void *elem;
-
- if (type >= M_LAST)
- panic("_malloc_zone TYPE");
-
- kmz = &kmzones[type];
- if (kmz->kz_zalloczone == KMZ_MALLOC)
- panic("_malloc_zone ZONE: type = %d", type);
-
-/* XXX */
- if (kmz->kz_elemsize == -1)
- panic("_malloc_zone XXX");
-/* XXX */
- if (size == kmz->kz_elemsize)
- if (flags & M_NOWAIT) {
- elem = (void *)zalloc_noblock(kmz->kz_zalloczone);
- } else {
- elem = (void *)zalloc(kmz->kz_zalloczone);
- }
- else
- if (flags & M_NOWAIT) {
- elem = (void *)kalloc_noblock(size);
- } else {
- elem = (void *)kalloc(size);
- }
+#pragma unused(oidp, arg1, arg2)
+ uint64_t zones_free_mem = get_zones_collectable_bytes();
- return (elem);
+ return SYSCTL_OUT(req, &zones_free_mem, sizeof(zones_free_mem));
}
-void
-_FREE_ZONE(
- void *elem,
- size_t size,
- int type)
+SYSCTL_PROC(_kern, OID_AUTO, zones_collectable_bytes,
+ CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_MASKED | CTLFLAG_LOCKED,
+ 0, 0, &sysctl_zones_collectable_bytes, "Q", "Collectable memory in zones");
+
+
+#if DEBUG || DEVELOPMENT
+
+static int
+sysctl_zone_gc_replenish_test SYSCTL_HANDLER_ARGS
+{
+#pragma unused(oidp, arg1, arg2)
+ /* require setting this sysctl to prevent sysctl -a from running this */
+ if (!req->newptr) {
+ return 0;
+ }
+
+ int ret_val = 0;
+ zone_gc_replenish_test();
+ return SYSCTL_OUT(req, &ret_val, sizeof(ret_val));
+}
+
+static int
+sysctl_zone_alloc_replenish_test SYSCTL_HANDLER_ARGS
{
- struct kmzones *kmz;
-
- if (type >= M_LAST)
- panic("FREE_SIZE");
-
- kmz = &kmzones[type];
- if (kmz->kz_zalloczone == KMZ_MALLOC)
- panic("free_zone ZONE");
-
-/* XXX */
- if (kmz->kz_elemsize == -1)
- panic("FREE_SIZE XXX");
-/* XXX */
- if (size == kmz->kz_elemsize)
- zfree(kmz->kz_zalloczone, elem);
- else
- kfree(elem, size);
+#pragma unused(oidp, arg1, arg2)
+ /* require setting this sysctl to prevent sysctl -a from running this */
+ if (!req->newptr) {
+ return 0;
+ }
+
+ int ret_val = 0;
+ zone_alloc_replenish_test();
+ return SYSCTL_OUT(req, &ret_val, sizeof(ret_val));
}
+
+SYSCTL_PROC(_kern, OID_AUTO, zone_gc_replenish_test,
+ CTLTYPE_INT | CTLFLAG_MASKED | CTLFLAG_LOCKED | CTLFLAG_WR,
+ 0, 0, &sysctl_zone_gc_replenish_test, "I", "Test zone GC replenish");
+SYSCTL_PROC(_kern, OID_AUTO, zone_alloc_replenish_test,
+ CTLTYPE_INT | CTLFLAG_MASKED | CTLFLAG_LOCKED | CTLFLAG_WR,
+ 0, 0, &sysctl_zone_alloc_replenish_test, "I", "Test zone alloc replenish");
+
+#endif /* DEBUG || DEVELOPMENT */