]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/kern_malloc.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / kern / kern_malloc.c
index a1c8f1b5084dbc7d461566c075497c6d969953ff..199f0eb7acd533df98313584d59243b8721f2105 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
  *
  * @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
  * 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,
@@ -22,7 +22,7 @@
  * 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 */
  * Version 2.0.
  */
 
-#include <sys/param.h>
+#include <kern/zalloc.h>
+#include <kern/kalloc.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>
-#include <sys/resourcevar.h>
-#include <sys/signalvar.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/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;
+       }
 
-void kmeminit(void) __attribute__((section("__TEXT, initcode")));
+       if (flags & (M_NOWAIT | M_NULL)) {
+               return NULL;
+       }
 
-/* Strings corresponding to types of memory.
- * Must be in synch with the #defines is sys/malloc.h 
- * NOTE - the reason we pass null strings in some cases is to reduce of foot
- * print as much as possible for systems where a tiny kernel is needed.
- * todo - We should probably redsign this and use enums for our types and only
- * include types needed for that configuration of the kernel.  This can't be
- * done without some kind of kpi since several types are hardwired and exported
- * (for example see types M_HFSMNT, M_UDFMNT, M_TEMP, etc in sys/malloc.h)
- */
-const char *memname[] = {
-       "free",         /* 0 M_FREE */
-       "mbuf",         /* 1 M_MBUF */
-       "devbuf",       /* 2 M_DEVBUF */ 
-       "socket",       /* 3 M_SOCKET */ 
-       "pcb",          /* 4 M_PCB */ 
-       "routetbl",     /* 5 M_RTABLE */ 
-       "hosttbl",      /* 6 M_HTABLE */ 
-       "fragtbl",      /* 7 M_FTABLE */ 
-       "zombie",       /* 8 M_ZOMBIE */ 
-       "ifaddr",       /* 9 M_IFADDR */ 
-       "soopts",       /* 10 M_SOOPTS */ 
-       "soname",       /* 11 M_SONAME */ 
-       "namei",        /* 12 M_NAMEI */ 
-       "gprof",        /* 13 M_GPROF */ 
-       "ioctlops",     /* 14 M_IOCTLOPS */ 
-       "mapmem",       /* 15 M_MAPMEM */ 
-       "cred",         /* 16 M_CRED */ 
-       "pgrp",         /* 17 M_PGRP */ 
-       "session",      /* 18 M_SESSION */ 
-       "iov32",        /* 19 M_IOV32 */ 
-       "mount",        /* 20 M_MOUNT */ 
-       "fhandle",              /* 21 M_FHANDLE */ 
-#if (NFSCLIENT || NFSSERVER)
-       "NFS req",              /* 22 M_NFSREQ */ 
-       "NFS mount",    /* 23 M_NFSMNT */ 
-       "NFS node",             /* 24 M_NFSNODE */ 
-#else
-       "",                             /* 22 M_NFSREQ */ 
-       "",                             /* 23 M_NFSMNT */ 
-       "",                             /* 24 M_NFSNODE */ 
-#endif
-       "vnodes",               /* 25 M_VNODE */ 
-       "namecache",    /* 26 M_CACHE */ 
-#if QUOTA
-       "UFS quota",    /* 27 M_DQUOT */ 
-#else
-       "",                             /* 27 M_DQUOT */ 
-#endif
-#if FFS
-       "UFS mount",    /* 28 M_UFSMNT */ 
-#else
-       "",                             /* 28 M_UFSMNT */ 
-#endif
-#if (SYSV_SEM || SYSV_MSG || SYSV_SHM)
-       "shm",                  /* 29 M_SHM */ 
-#else
-       "",                             /* 29 M_SHM */ 
-#endif
-       "plimit",               /* 30 M_VMMAP */ 
-       "sigacts",      /* 31 M_VMMAPENT */ 
-       "VM object",    /* 32 M_VMOBJ */ 
-       "VM objhash",   /* 33 M_VMOBJHASH */ 
-       "VM pmap",              /* 34 M_VMPMAP */ 
-       "VM pvmap",             /* 35 M_VMPVENT */ 
-       "VM pager",             /* 36 M_VMPAGER */ 
-       "VM pgdata",    /* 37 M_VMPGDATA */ 
-       "fileproc",             /* 38 M_FILEPROC */ 
-       "file desc",    /* 39 M_FILEDESC */ 
-       "lockf",                /* 40 M_LOCKF */ 
-       "proc",                 /* 41 M_PROC */ 
-       "pstats",               /* 42 M_SUBPROC */ 
-       "LFS segment",  /* 43 M_SEGMENT */ 
-       "LFS node",             /* 44 M_LFSNODE */ 
-#if FFS
-       "FFS node",             /* 45 M_FFSNODE */ 
-#else
-       "",                             /* 45 M_FFSNODE */ 
-#endif
-       "MFS node",             /* 46 M_MFSNODE */ 
-       "NQNFS Lease",  /* 47 M_NQLEASE */ 
-       "NQNFS Host",   /* 48 M_NQMHOST */ 
-       "Export Host",  /* 49 M_NETADDR */ 
-#if (NFSCLIENT || NFSSERVER)
-       "NFS srvsock",  /* 50 M_NFSSVC */ 
-       "NFS uid",              /* 51 M_NFSUID */ 
-       "NFS daemon",   /* 52 M_NFSD */ 
-#else
-       "",                             /* 50 M_NFSSVC */ 
-       "",                             /* 51 M_NFSUID */ 
-       "",                             /* 52 M_NFSD */ 
-#endif
-       "ip_moptions",  /* 53 M_IPMOPTS */ 
-       "in_multi",             /* 54 M_IPMADDR */ 
-       "ether_multi",  /* 55 M_IFMADDR */ 
-       "mrt",                  /* 56 M_MRTABLE */ 
-#if CD9660
-       "ISOFS mount",  /* 57 M_ISOFSMNT */ 
-       "ISOFS node",   /* 58 M_ISOFSNODE */ 
-#else
-       "",                             /* 57 M_ISOFSMNT */ 
-       "",                             /* 58 M_ISOFSNODE */ 
-#endif
-#if (NFSCLIENT || NFSSERVER)
-       "NFSV3 srvdesc",/* 59 M_NFSRVDESC */ 
-       "NFSV3 diroff", /* 60 M_NFSDIROFF */ 
-       "NFSV3 bigfh",  /* 61 M_NFSBIGFH */ 
-#else
-       "",                             /* 59 M_NFSRVDESC */ 
-       "",                             /* 60 M_NFSDIROFF */ 
-       "",                             /* 61 M_NFSBIGFH */ 
-#endif
-       "MSDOSFS mount",/* 62 M_MSDOSFSMNT */ 
-       "MSDOSFS fat",  /* 63 M_MSDOSFSFAT */ 
-       "MSDOSFS node", /* 64 M_MSDOSFSNODE */ 
-       "ttys",                 /* 65 M_TTYS */ 
-       "exec",                 /* 66 M_EXEC */ 
-       "miscfs mount", /* 67 M_MISCFSMNT */ 
-       "miscfs node",  /* 68 M_MISCFSNODE */ 
-       "adosfs mount", /* 69 M_ADOSFSMNT */ 
-       "adosfs node",  /* 70 M_ADOSFSNODE */ 
-       "adosfs anode", /* 71 M_ANODE */ 
-       "buf hdrs",             /* 72 M_BUFHDR */ 
-       "ofile tabl",   /* 73 M_OFILETABL */ 
-       "mbuf clust",   /* 74 M_MCLUST */ 
-#if HFS
-       "HFS mount",    /* 75 M_HFSMNT */ 
-       "HFS node",             /* 76 M_HFSNODE */ 
-       "HFS fork",             /* 77 M_HFSFORK */ 
-#else
-       "",                             /* 75 M_HFSMNT */ 
-       "",                             /* 76 M_HFSNODE */ 
-       "",                             /* 77 M_HFSFORK */ 
-#endif
-       "ZFS mount",    /* 78 M_ZFSFSMNT */ 
-       "ZFS node",     /* 79 M_ZFSNODE */ 
-       "temp",                 /* 80 M_TEMP */ 
-       "key mgmt",             /* 81 M_SECA */ 
-       "DEVFS",                /* 82 M_DEVFS */ 
-       "IpFw/IpAcct",  /* 83 M_IPFW */ 
-       "UDF node",             /* 84 M_UDFNODE */ 
-       "UDF mount",    /* 85 M_UDFMNT */ 
-#if INET6
-       "IPv6 NDP",             /* 86 M_IP6NDP */ 
-       "IPv6 options", /* 87 M_IP6OPT */ 
-       "IPv6 Misc",    /* 88 M_IP6MISC */
-#else
-       "",                             /* 86 M_IP6NDP */ 
-       "",                             /* 87 M_IP6OPT */ 
-       "",                             /* 88 M_IP6MISC */
-#endif
-       "TCP Segment Q",/* 89 M_TSEGQ */
-       "IGMP state",   /* 90 M_IGMP */
-#if JOURNALING
-       "Journal",              /* 91 M_JNL_JNL */
-       "Transaction",  /* 92 M_JNL_TR */
-#else
-       "",                     /* 91 M_JNL_JNL */
-       "",                     /* 92 M_JNL_TR */
-#endif
-       "specinfo",             /* 93 M_SPECINFO */
-       "kqueue",               /* 94 M_KQUEUE */
-#if HFS
-       "HFS dirhint",  /* 95 M_HFSDIRHINT */ 
-#else
-       "",                             /* 95 M_HFSDIRHINT */ 
-#endif
-       "cluster_read", /* 96 M_CLRDAHEAD */ 
-       "cluster_write",/* 97 M_CLWRBEHIND */ 
-       "iov64",                /* 98 M_IOV64 */ 
-       "fileglob",             /* 99 M_FILEGLOB */ 
-       "kauth",                /* 100 M_KAUTH */ 
-       "dummynet",             /* 101 M_DUMMYNET */ 
-       "unsafe_fsnode",        /* 102 M_UNSAFEFS */ 
-       "macpipelabel", /* 103 M_MACPIPELABEL */
-       "mactemp",      /* 104 M_MACTEMP */
-       "sbuf",         /* 105 M_SBUF */
-       "extattr",      /* 106 M_EXTATTR */
-       "lctx",         /* 107 M_LCTX */
-#if TRAFFIC_MGT
-       "traffic_mgt",   /* 108 M_TRAFFIC_MGT */
-#else
-       "", /* 108 M_TRAFFIC_MGT */
-#endif
-};
-
-/* for use with kmzones.kz_zalloczone */
-#define        KMZ_CREATEZONE          ((void *)-2)
-#define KMZ_LOOKUPZONE         ((void *)-1)
-#define KMZ_MALLOC                     ((void *)0)
-#define        KMZ_SHAREZONE           ((void *)1)
-
-struct kmzones {
-       size_t          kz_elemsize;
-       void            *kz_zalloczone;
-} 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 */
-#if (NFSCLIENT || NFSSERVER)
-       { SOS(nfsreq),  KMZ_CREATEZONE },       /* 22 M_NFSREQ */
-       { SOS(nfsmount),        KMZ_CREATEZONE },       /* 23 M_NFSMNT */
-       { SOS(nfsnode), KMZ_CREATEZONE },       /* 24 M_NFSNODE */
-#else
-       { 0,            KMZ_MALLOC },           /* 22 M_NFSREQ */
-       { 0,            KMZ_MALLOC },           /* 23 M_NFSMNT */
-       { 0,            KMZ_MALLOC },           /* 24 M_NFSNODE */
-#endif
-       { SOS(vnode),   KMZ_CREATEZONE },       /* 25 M_VNODE */
-       { SOS(namecache),       KMZ_CREATEZONE },       /* 26 M_CACHE */
-#if QUOTA
-       { SOX(dquot),   KMZ_LOOKUPZONE },       /* 27 M_DQUOT */
-#else
-       { 0,            KMZ_MALLOC },           /* 27 M_DQUOT */
-#endif
-#if FFS
-       { SOX(ufsmount),        KMZ_LOOKUPZONE },       /* 28 M_UFSMNT */
-#else
-       { 0,            KMZ_MALLOC },           /* 28 M_UFSMNT */
-#endif
-       { 0,            KMZ_MALLOC },           /* 29 M_CGSUM */
-       { SOS(plimit),  KMZ_CREATEZONE },       /* 30 M_PLIMIT */
-       { SOS(sigacts), KMZ_CREATEZONE },       /* 31 M_SIGACTS */
-       { 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_PSTATS */
-       { 0,            KMZ_MALLOC },           /* 43 M_SEGMENT */
-       { M_FFSNODE,    KMZ_SHAREZONE },        /* 44 M_LFSNODE */
-#if FFS
-       { SOS(inode),   KMZ_CREATEZONE },       /* 45 M_FFSNODE */
-#else
-       { 0,            KMZ_MALLOC },           /* 45 M_FFSNODE */
-#endif
-       { 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 */
-#if (NFSCLIENT || NFSSERVER)
-       { SOX(nfsrv_sock),
-                       KMZ_CREATEZONE },       /* 50 M_NFSSVC */
-       { 0,            KMZ_MALLOC },           /* 51 M_NFSUID */
-       { SOX(nfsrvcache),
-                       KMZ_CREATEZONE },       /* 52 M_NFSD */
-#else
-       { 0,            KMZ_MALLOC },           /* 50 M_NFSSVC */
-       { 0,            KMZ_MALLOC },           /* 51 M_NFSUID */
-       { 0,            KMZ_MALLOC },           /* 52 M_NFSD */
-#endif
-       { 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 */
-#if CD9660
-       { SOX(iso_mnt), KMZ_LOOKUPZONE },       /* 57 M_ISOFSMNT */
-       { SOS(iso_node),        KMZ_CREATEZONE },       /* 58 M_ISOFSNODE */
-#else
-       { 0,            KMZ_MALLOC },           /* 57 M_ISOFSMNT */
-       { 0,            KMZ_MALLOC },           /* 58 M_ISOFSNODE */
-#endif
-#if (NFSCLIENT || NFSSERVER)
-       { SOS(nfsrv_descript),
-                       KMZ_CREATEZONE },       /* 59 M_NFSRVDESC */
-       { SOS(nfsdmap), KMZ_CREATEZONE },       /* 60 M_NFSDIROFF */
-       { SOS(fhandle), KMZ_LOOKUPZONE },       /* 61 M_NFSBIGFH */
-#else
-       { 0,            KMZ_MALLOC },           /* 59 M_NFSRVDESC */
-       { 0,            KMZ_MALLOC },           /* 60 M_NFSDIROFF */
-       { 0,            KMZ_MALLOC },           /* 61 M_NFSBIGFH */
-#endif
-       { 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 */
-#if HFS
-       { SOX(hfsmount),        KMZ_LOOKUPZONE },       /* 75 M_HFSMNT */
-       { SOS(cnode),   KMZ_CREATEZONE },       /* 76 M_HFSNODE */
-       { SOS(filefork),        KMZ_CREATEZONE },       /* 77 M_HFSFORK */
-#else
-       { 0,            KMZ_MALLOC },           /* 75 M_HFSMNT */
-       { 0,            KMZ_MALLOC },           /* 76 M_HFSNODE */
-       { 0,            KMZ_MALLOC },           /* 77 M_HFSFORK */
-#endif
-       { 0,            KMZ_MALLOC },           /* 78 M_ZFSMNT */
-       { 0,            KMZ_MALLOC },           /* 79 M_ZFSNODE */
-       { 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 */
-#if JOURNALING
-       { SOS(journal), KMZ_CREATEZONE },       /* 91 M_JNL_JNL */
-       { SOS(transaction), KMZ_CREATEZONE },   /* 92 M_JNL_TR */
-#else
-       { 0,     KMZ_MALLOC },          /* 91 M_JNL_JNL */
-       { 0,     KMZ_MALLOC },          /* 92 M_JNL_TR */
-#endif
-       { SOS(specinfo), KMZ_CREATEZONE },      /* 93 M_SPECINFO */
-       { SOS(kqueue), KMZ_CREATEZONE },        /* 94 M_KQUEUE */
-#if HFS
-       { SOS(directoryhint), KMZ_CREATEZONE }, /* 95 M_HFSDIRHINT */
-#else
-       { 0,    KMZ_MALLOC },           /* 95 M_HFSDIRHINT */
-#endif
-       { 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 */
-       { 0,            KMZ_MALLOC },           /* 103 M_MACPIPELABEL */
-       { 0,            KMZ_MALLOC },           /* 104 M_MACTEMP */
-       { 0,            KMZ_MALLOC },           /* 105 M_SBUF */
-       { 0,            KMZ_MALLOC },           /* 106 M_HFS_EXTATTR */
-       { 0,            KMZ_MALLOC },           /* 107 M_LCTX */
-       { 0,            KMZ_MALLOC },           /* 108 M_TRAFFIC_MGT */
-#undef SOS
-#undef SOX
-};
-
-extern zone_t kalloc_zone(vm_size_t);  /* XXX */
+       panic("_REALLOC: kalloc returned NULL (potential leak), size %llu", (uint64_t) size);
+}
 
-/*
- * Initialize the kernel memory allocator
- */
+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);
+}
+
+void
+_FREE_external(void *addr, int type);
 void
-kmeminit(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 %lu elements but memname has %lu\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 == (size_t)(-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 == (size_t)(-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");
 
-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");
 
-       if (size == 0)
-               return (NULL);
+/*
+ * 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;
 
-       if (flags & M_NOWAIT) {
-               mem = (void *)kalloc_noblock(memsize);
-       } else {
-               mem = (void *)kalloc(memsize);
+       val = oldval = get_zleak_state();
+       error = sysctl_handle_int(oidp, &val, 0, req);
+       if (error || !req->newptr) {
+               return error;
+       }
+       /*
+        * Can only be activated if it's off (and not failed.)
+        * Cannot be deactivated once it's on.
+        */
+       if (val == 1 && oldval == 0) {
+               kern_return_t kr = zleak_activate();
+
+               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;
+
+       error = sysctl_io_number(req, value, sizeof(value), &value, NULL);
 
-       if (type >= M_LAST)
-               panic("_free TYPE");
+       if (error || !req->newptr) {
+               return error;
+       }
 
-       if (!addr)
-               return; /* correct (convenient bsd kernel legacy) */
+       if (value > (uint64_t)zleak_max_zonemap_size) {
+               return ERANGE;
+       }
 
-       hdr = addr; hdr--;
-       kfree(hdr, hdr->mlen);
+       *(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 == (size_t)(-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
 {
-       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 == (size_t)(-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_gc_replenish_test();
+       return SYSCTL_OUT(req, &ret_val, sizeof(ret_val));
 }
+
+static int
+sysctl_zone_alloc_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_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 */