1/* 2 * Copyright (c) 2000-2014 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * Copyright (c) 1992,7 NeXT Computer, Inc. 30 * 31 * Unix data structure initialization. 32 * 33 */ 34 35#include <mach/mach_types.h> 36 37#include <vm/vm_kern.h> 38#include <mach/vm_prot.h> 39 40#include <sys/param.h> 41#include <sys/buf_internal.h> 42#include <sys/file_internal.h> 43#include <sys/proc_internal.h> 44#include <sys/clist.h> 45#include <sys/mcache.h> 46#include <sys/mbuf.h> 47#include <sys/systm.h> 48#include <sys/tty.h> 49#include <sys/vnode.h> 50#include <sys/sysctl.h> 51#include <machine/cons.h> 52#include <pexpert/pexpert.h> 53#include <sys/socketvar.h> 54#include <pexpert/pexpert.h> 55 56extern uint32_t kern_maxvnodes; 57extern vm_map_t mb_map; 58 59#if INET || INET6 60extern uint32_t tcp_sendspace; 61extern uint32_t tcp_recvspace; 62#endif 63 64void bsd_bufferinit(void); 65extern void md_prepare_for_shutdown(int, int, char *); 66 67unsigned int bsd_mbuf_cluster_reserve(boolean_t *); 68void bsd_scale_setup(int); 69void bsd_exec_setup(int); 70 71/* 72 * Declare these as initialized data so we can patch them. 73 */ 74 75#ifdef NBUF 76int max_nbuf_headers = NBUF; 77int niobuf_headers = (NBUF / 2) + 2048; 78int nbuf_hashelements = NBUF; 79int nbuf_headers = NBUF; 80#else 81int max_nbuf_headers = 0; 82int niobuf_headers = 0; 83int nbuf_hashelements = 0; 84int nbuf_headers = 0; 85#endif 86 87SYSCTL_INT (_kern, OID_AUTO, nbuf, CTLFLAG_RD | CTLFLAG_LOCKED, &nbuf_headers, 0, ""); 88SYSCTL_INT (_kern, OID_AUTO, maxnbuf, CTLFLAG_RW | CTLFLAG_LOCKED, &max_nbuf_headers, 0, ""); 89 90__private_extern__ int customnbuf = 0; 91int serverperfmode = 0; /* Flag indicates a server boot when set */ 92int ncl = 0; 93 94#if SOCKETS 95static unsigned int mbuf_poolsz; 96#endif 97 98vm_map_t buffer_map; 99vm_map_t bufferhdr_map; 100static int vnodes_sized = 0; 101 102extern void bsd_startupearly(void); 103 104void 105bsd_startupearly(void) 106{ 107 vm_offset_t firstaddr; 108 vm_size_t size; 109 kern_return_t ret; 110 111 /* clip the number of buf headers upto 16k */ 112 if (max_nbuf_headers == 0) 113 max_nbuf_headers = atop_kernel(sane_size / 50); /* Get 2% of ram, but no more than we can map */ 114 if ((customnbuf == 0) && (max_nbuf_headers > 16384)) 115 max_nbuf_headers = 16384; 116 if (max_nbuf_headers < CONFIG_MIN_NBUF) 117 max_nbuf_headers = CONFIG_MIN_NBUF; 118 119 /* clip the number of hash elements to 200000 */ 120 if ( (customnbuf == 0 ) && nbuf_hashelements == 0) { 121 nbuf_hashelements = atop_kernel(sane_size / 50); 122 if (nbuf_hashelements > 200000) 123 nbuf_hashelements = 200000; 124 } else 125 nbuf_hashelements = max_nbuf_headers; 126 127 if (niobuf_headers == 0) { 128 if (max_nbuf_headers < 4096) 129 niobuf_headers = max_nbuf_headers; 130 else 131 niobuf_headers = (max_nbuf_headers / 2) + 2048; 132 } 133 if (niobuf_headers < CONFIG_MIN_NIOBUF) 134 niobuf_headers = CONFIG_MIN_NIOBUF; 135 136 size = (max_nbuf_headers + niobuf_headers) * sizeof(struct buf); 137 size = round_page(size); 138 139 ret = kmem_suballoc(kernel_map, 140 &firstaddr, 141 size, 142 FALSE, 143 VM_FLAGS_ANYWHERE, 144 &bufferhdr_map); 145 146 if (ret != KERN_SUCCESS) 147 panic("Failed to create bufferhdr_map"); 148 149 ret = kernel_memory_allocate(bufferhdr_map, 150 &firstaddr, 151 size, 152 0, 153 KMA_HERE | KMA_KOBJECT); 154 155 if (ret != KERN_SUCCESS) 156 panic("Failed to allocate bufferhdr_map"); 157 158 buf_headers = (struct buf *) firstaddr; 159 bzero(buf_headers, size); 160 161#if SOCKETS 162 { 163 static const unsigned int maxspace = 128 * 1024; 164 int scale; 165 166 nmbclusters = bsd_mbuf_cluster_reserve(NULL) / MCLBYTES; 167 168#if INET || INET6 169 if ((scale = nmbclusters / NMBCLUSTERS) > 1) { 170 tcp_sendspace *= scale; 171 tcp_recvspace *= scale; 172 173 if (tcp_sendspace > maxspace) 174 tcp_sendspace = maxspace; 175 if (tcp_recvspace > maxspace) 176 tcp_recvspace = maxspace; 177 } 178#endif /* INET || INET6 */ 179 } 180#endif /* SOCKETS */ 181 182 if (vnodes_sized == 0) { 183 if (!PE_get_default("kern.maxvnodes", &desiredvnodes, sizeof(desiredvnodes))) { 184 /* 185 * Size vnodes based on memory 186 * Number vnodes is (memsize/64k) + 1024 187 * This is the calculation that is used by launchd in tiger 188 * we are clipping the max based on 16G 189 * ie ((16*1024*1024*1024)/(64 *1024)) + 1024 = 263168; 190 * CONFIG_VNODES is set to 263168 for "medium" configurations (the default) 191 * but can be smaller or larger. 192 */ 193 desiredvnodes = (sane_size/65536) + 1024; 194#ifdef CONFIG_VNODES 195 if (desiredvnodes > CONFIG_VNODES) 196 desiredvnodes = CONFIG_VNODES; 197#endif 198 } 199 vnodes_sized = 1; 200 } 201} 202 203void 204bsd_bufferinit(void) 205{ 206#if SOCKETS 207 kern_return_t ret; 208#endif 209 /* 210 * Note: Console device initialized in kminit() from bsd_autoconf() 211 * prior to call to us in bsd_init(). 212 */ 213 214 bsd_startupearly(); 215 216#if SOCKETS 217 ret = kmem_suballoc(kernel_map, 218 (vm_offset_t *) & mbutl, 219 (vm_size_t) (nmbclusters * MCLBYTES), 220 FALSE, 221 VM_FLAGS_ANYWHERE, 222 &mb_map); 223 224 if (ret != KERN_SUCCESS) 225 panic("Failed to allocate mb_map\n"); 226#endif /* SOCKETS */ 227 228 /* 229 * Set up buffers, so they can be used to read disk labels. 230 */ 231 bufinit(); 232} 233 234/* 512 MB (K32) or 2 GB (K64) hard limit on size of the mbuf pool */ 235#if !defined(__LP64__) 236#define MAX_MBUF_POOL (512 << MBSHIFT) 237#else 238#define MAX_MBUF_POOL (2ULL << GBSHIFT) 239#endif /* !__LP64__ */ 240#define MAX_NCL (MAX_MBUF_POOL >> MCLSHIFT) 241 242#if SOCKETS 243/* 244 * this has been broken out into a separate routine that 245 * can be called from the x86 early vm initialization to 246 * determine how much lo memory to reserve on systems with 247 * DMA hardware that can't fully address all of the physical 248 * memory that is present. 249 */ 250unsigned int 251bsd_mbuf_cluster_reserve(boolean_t *overridden) 252{ 253 int mbuf_pool = 0; 254 static boolean_t was_overridden = FALSE; 255 256 /* If called more than once, return the previously calculated size */ 257 if (mbuf_poolsz != 0) 258 goto done; 259 260 /* 261 * Some of these are parsed in parse_bsd_args(), but for x86 we get 262 * here early from i386_vm_init() and so we parse them now, in order 263 * to correctly compute the size of the low-memory VM pool. It is 264 * redundant but rather harmless. 265 */ 266 (void) PE_parse_boot_argn("ncl", &ncl, sizeof (ncl)); 267 (void) PE_parse_boot_argn("mbuf_pool", &mbuf_pool, sizeof (mbuf_pool)); 268 269 /* 270 * Convert "mbuf_pool" from MB to # of 2KB clusters; it is 271 * equivalent to "ncl", except that it uses different unit. 272 */ 273 if (mbuf_pool != 0) 274 ncl = (mbuf_pool << MBSHIFT) >> MCLSHIFT; 275 276 if (sane_size > (64 * 1024 * 1024) || ncl != 0) { 277 278 if (ncl || serverperfmode) 279 was_overridden = TRUE; 280 281 if ((nmbclusters = ncl) == 0) { 282 /* Auto-configure the mbuf pool size */ 283 nmbclusters = mbuf_default_ncl(serverperfmode, sane_size); 284 } else { 285 /* Make sure it's not odd in case ncl is manually set */ 286 if (nmbclusters & 0x1) 287 --nmbclusters; 288 289 /* And obey the upper limit */ 290 if (nmbclusters > MAX_NCL) 291 nmbclusters = MAX_NCL; 292 } 293 294 /* Round it down to nearest multiple of 4KB clusters */ 295 nmbclusters = P2ROUNDDOWN(nmbclusters, NCLPBG); 296 } 297 mbuf_poolsz = nmbclusters << MCLSHIFT; 298done: 299 if (overridden) 300 *overridden = was_overridden; 301 302 return (mbuf_poolsz); 303} 304#endif 305 306#if defined(__LP64__) 307extern int tcp_tcbhashsize; 308extern int max_cached_sock_count; 309#endif 310 311 312void 313bsd_scale_setup(int scale) 314{ 315#if defined(__LP64__) 316 if ((scale > 0) && (serverperfmode == 0)) { 317 maxproc *= scale; 318 maxprocperuid = (maxproc * 2) / 3; 319 } 320 /* Apply server scaling rules */ 321 if ((scale > 0) && (serverperfmode !=0)) { 322 maxproc = 2500 * scale; 323 hard_maxproc = maxproc; 324 /* no fp usage */ 325 maxprocperuid = (maxproc*3)/4; 326 maxfiles = (150000 * scale); 327 maxfilesperproc = maxfiles/2; 328 desiredvnodes = maxfiles; 329 vnodes_sized = 1; 330 if (scale > 4) { 331 /* clip somaxconn at 32G level */ 332 somaxconn = 2048; 333 /* 334 * For scale > 4 (> 32G), clip 335 * tcp_tcbhashsize to 32K 336 */ 337 tcp_tcbhashsize = 32 *1024; 338 339 if (scale > 7) { 340 /* clip at 64G level */ 341 max_cached_sock_count = 165000; 342 } else { 343 max_cached_sock_count = 60000 + ((scale-1) * 15000); 344 } 345 } else { 346 somaxconn = 512*scale; 347 tcp_tcbhashsize = 4*1024*scale; 348 max_cached_sock_count = 60000 + ((scale-1) * 15000); 349 } 350 } 351#endif 352 bsd_exec_setup(scale); 353} 354 355