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