1 /*
2 * Copyright (c) 2016-2021 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 /* BEGIN CSTYLED */
30 /*
31 * SKMEM_ARENA_TYPE_NEXUS:
32 *
33 * This arena represents the memory subsystem of a nexus adapter. It consist
34 * of a collection of memory regions that are usable by the nexus, as well
35 * as the various caches for objects in those regions.
36 *
37 * (1 per nexus adapter)
38 * +=======================+
39 * | skmem_arena |
40 * +-----------------------+ (backing regions)
41 * | ar_regions[0] | +=======================+
42 * : ... : ------->> | skmem_region |===+
43 * | ar_regions[n] | +=======================+ |===+
44 * +=======================+ +=======================+ |
45 * | arn_{caches,pp} | ---+ +=======================+
46 * +-----------------------+ |
47 * | arn_stats_obj | |
48 * | arn_flowadv_obj | | (cache frontends)
49 * | arn_nexusadv_obj | | +=======================+
50 * +-----------------------+ +--->> | skmem_cache |===+
51 * +=======================+ |===+
52 * +=======================+ |
53 * +=======================+
54 *
55 * Three regions {umd,kmd,buf} are used for the packet buffer pool, which
56 * may be external to the nexus adapter, e.g. created by the driver or an
57 * external entity. If not supplied, we create these regions along with
58 * the packet buffer pool ourselves. The rest of the regions (unrelated
59 * to the packet buffer pool) are unique to the arena and are allocated at
60 * arena creation time.
61 *
62 * An arena may be mapped to a user task/process for as many times as needed.
63 * The result of each mapping is a contiguous range within the address space
64 * of that task, indicated by [ami_mapaddr, ami_mapaddr + ami_mapsize) span.
65 * This is achieved by leveraging the mapper memory object ar_mapper that
66 * "stitches" the disjoint segments together. Only user-mappable regions,
67 * i.e. those marked with SKR_MODE_MMAPOK, will be included in this span.
68 *
69 * Nexus adapters that are eligible for defunct will trigger the arena to
70 * undergo memory redirection for all regions except those that are marked
71 * with SKR_MODE_NOREDIRECT. This happens when all of the channels opened
72 * to the adapter are defunct. Upon completion, those redirected regions
73 * will be torn down in order to reduce their memory footprints. When this
74 * happens the adapter and its arena are no longer active or in service.
75 *
76 * The arena exposes caches for allocating and freeing most region objects.
77 * These slab-allocator based caches act as front-ends to the regions; only
78 * the metadata cache (for kern_packet_t) utilizes the magazines layer. All
79 * other ones simply utilize skmem_cache for slab-based allocations.
80 *
81 * Certain regions contain singleton objects that are simple enough to not
82 * require the slab allocator, such as the ones used for statistics and flow
83 * advisories. Because of this, we directly allocate from those regions
84 * and store the objects in the arena.
85 *
86 * SKMEM_ARENA_TYPE_NECP:
87 *
88 * This arena represents the memory subsystem of an NECP file descriptor
89 * object. It consists of a memory region for per-flow statistics, as well
90 * as a cache front-end for that region.
91 *
92 * SKMEM_ARENA_SYSTEM:
93 *
94 * This arena represents general, system-wide objects. It currently
95 * consists of the sysctls region that's created once at init time.
96 */
97 /* END CSTYLED */
98
99 #include <skywalk/os_skywalk_private.h>
100 #include <net/necp.h>
101
102 static void skmem_arena_destroy(struct skmem_arena *);
103 static void skmem_arena_teardown(struct skmem_arena *, boolean_t);
104 static int skmem_arena_create_finalize(struct skmem_arena *);
105 static void skmem_arena_nexus_teardown(struct skmem_arena_nexus *, boolean_t);
106 static void skmem_arena_necp_teardown(struct skmem_arena_necp *, boolean_t);
107 static void skmem_arena_system_teardown(struct skmem_arena_system *, boolean_t);
108 static void skmem_arena_init_common(struct skmem_arena *ar,
109 skmem_arena_type_t type, size_t ar_zsize, const char *ar_str, const char *name);
110 static void skmem_arena_free(struct skmem_arena *);
111 static void skmem_arena_retain_locked(struct skmem_arena *);
112 static void skmem_arena_reap_locked(struct skmem_arena *, boolean_t);
113 static boolean_t skmem_arena_munmap_common(struct skmem_arena *,
114 struct skmem_arena_mmap_info *);
115 #if SK_LOG
116 static void skmem_arena_create_region_log(struct skmem_arena *);
117 #endif /* SK_LOG */
118 static int skmem_arena_mib_get_sysctl SYSCTL_HANDLER_ARGS;
119
120 SYSCTL_PROC(_kern_skywalk_stats, OID_AUTO, arena,
121 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED,
122 0, 0, skmem_arena_mib_get_sysctl, "S,sk_stats_arena",
123 "Skywalk arena statistics");
124
125 static LCK_GRP_DECLARE(skmem_arena_lock_grp, "skmem_arena");
126 static LCK_MTX_DECLARE(skmem_arena_lock, &skmem_arena_lock_grp);
127
128 static TAILQ_HEAD(, skmem_arena) skmem_arena_head = TAILQ_HEAD_INITIALIZER(skmem_arena_head);
129
130 #define SKMEM_ARENA_LOCK() \
131 lck_mtx_lock(&skmem_arena_lock)
132 #define SKMEM_ARENA_LOCK_ASSERT_HELD() \
133 LCK_MTX_ASSERT(&skmem_arena_lock, LCK_MTX_ASSERT_OWNED)
134 #define SKMEM_ARENA_LOCK_ASSERT_NOTHELD() \
135 LCK_MTX_ASSERT(&skmem_arena_lock, LCK_MTX_ASSERT_NOTOWNED)
136 #define SKMEM_ARENA_UNLOCK() \
137 lck_mtx_unlock(&skmem_arena_lock)
138
139 #define AR_NEXUS_SIZE sizeof(struct skmem_arena_nexus)
140 static SKMEM_TYPE_DEFINE(ar_nexus_zone, struct skmem_arena_nexus);
141
142 #define AR_NECP_SIZE sizeof(struct skmem_arena_necp)
143 static SKMEM_TYPE_DEFINE(ar_necp_zone, struct skmem_arena_necp);
144
145 #define AR_SYSTEM_SIZE sizeof(struct skmem_arena_system)
146 static SKMEM_TYPE_DEFINE(ar_system_zone, struct skmem_arena_system);
147
148 #define SKMEM_TAG_ARENA_MIB "com.apple.skywalk.arena.mib"
149 static SKMEM_TAG_DEFINE(skmem_tag_arena_mib, SKMEM_TAG_ARENA_MIB);
150
151 static_assert(SKMEM_ARENA_TYPE_NEXUS == SAR_TYPE_NEXUS);
152 static_assert(SKMEM_ARENA_TYPE_NECP == SAR_TYPE_NECP);
153 static_assert(SKMEM_ARENA_TYPE_SYSTEM == SAR_TYPE_SYSTEM);
154
155 SK_NO_INLINE_ATTRIBUTE
156 static int
skmem_arena_sd_setup(const struct nexus_adapter * na,struct skmem_region_params srp[SKMEM_REGIONS],struct skmem_arena * ar,boolean_t kernel_only,boolean_t tx)157 skmem_arena_sd_setup(const struct nexus_adapter *na,
158 struct skmem_region_params srp[SKMEM_REGIONS], struct skmem_arena *ar,
159 boolean_t kernel_only, boolean_t tx)
160 {
161 struct skmem_arena_nexus *arn = (struct skmem_arena_nexus *)ar;
162 struct skmem_cache **cachep;
163 struct skmem_region *ksd_skr = NULL, *usd_skr = NULL;
164 const char *__null_terminated name = NULL;
165 char cname[64];
166 skmem_region_id_t usd_type, ksd_type;
167 int err = 0;
168
169 usd_type = tx ? SKMEM_REGION_TXAUSD : SKMEM_REGION_RXFUSD;
170 ksd_type = tx ? SKMEM_REGION_TXAKSD : SKMEM_REGION_RXFKSD;
171 if (tx) {
172 usd_type = SKMEM_REGION_TXAUSD;
173 ksd_type = SKMEM_REGION_TXAKSD;
174 cachep = &arn->arn_txaksd_cache;
175 } else {
176 usd_type = SKMEM_REGION_RXFUSD;
177 ksd_type = SKMEM_REGION_RXFKSD;
178 cachep = &arn->arn_rxfksd_cache;
179 }
180 name = __unsafe_null_terminated_from_indexable(na->na_name);
181 ksd_skr = skmem_region_create(name, &srp[ksd_type], NULL, NULL, NULL);
182 if (ksd_skr == NULL) {
183 SK_ERR("\"%s\" ar 0x%llx flags %b failed to "
184 "create %s region", ar->ar_name, SK_KVA(ar),
185 ar->ar_flags, ARF_BITS, srp[ksd_type].srp_name);
186 err = ENOMEM;
187 goto failed;
188 }
189 ar->ar_regions[ksd_type] = ksd_skr;
190 if (!kernel_only) {
191 usd_skr = skmem_region_create(name, &srp[usd_type], NULL,
192 NULL, NULL);
193 if (usd_skr == NULL) {
194 err = ENOMEM;
195 goto failed;
196 }
197 ar->ar_regions[usd_type] = usd_skr;
198 skmem_region_mirror(ksd_skr, usd_skr);
199 }
200 name = tsnprintf(cname, sizeof(cname), "%s_ksd.%.*s",
201 tx ? "txa" : "rxf", (int)sizeof(na->na_name), na->na_name);
202 ASSERT(ar->ar_regions[ksd_type] != NULL);
203 *cachep = skmem_cache_create(name, srp[ksd_type].srp_c_obj_size, 0,
204 NULL, NULL, NULL, NULL, ar->ar_regions[ksd_type],
205 SKMEM_CR_NOMAGAZINES);
206 if (*cachep == NULL) {
207 SK_ERR("\"%s\" ar 0x%llx flags %b failed to create %s",
208 ar->ar_name, SK_KVA(ar), ar->ar_flags, ARF_BITS, cname);
209 err = ENOMEM;
210 goto failed;
211 }
212 return 0;
213
214 failed:
215 if (ksd_skr != NULL) {
216 skmem_region_release(ksd_skr);
217 ar->ar_regions[ksd_type] = NULL;
218 }
219 if (usd_skr != NULL) {
220 /*
221 * decrements refcnt incremented by skmem_region_mirror()
222 * this is not needed in case skmem_cache_create() succeeds
223 * because skmem_cache_destroy() does the release.
224 */
225 skmem_region_release(usd_skr);
226
227 /* decrements the region's own refcnt */
228 skmem_region_release(usd_skr);
229 ar->ar_regions[usd_type] = NULL;
230 }
231 return err;
232 }
233
234 SK_NO_INLINE_ATTRIBUTE
235 static void
skmem_arena_sd_teardown(struct skmem_arena * ar,boolean_t tx)236 skmem_arena_sd_teardown(struct skmem_arena *ar, boolean_t tx)
237 {
238 struct skmem_arena_nexus *arn = (struct skmem_arena_nexus *)ar;
239 struct skmem_cache **cachep;
240 struct skmem_region **ksd_rp, **usd_rp;
241
242 if (tx) {
243 cachep = &arn->arn_txaksd_cache;
244 ksd_rp = &ar->ar_regions[SKMEM_REGION_TXAKSD];
245 usd_rp = &ar->ar_regions[SKMEM_REGION_TXAUSD];
246 } else {
247 cachep = &arn->arn_rxfksd_cache;
248 ksd_rp = &ar->ar_regions[SKMEM_REGION_RXFKSD];
249 usd_rp = &ar->ar_regions[SKMEM_REGION_RXFUSD];
250 }
251 if (*cachep != NULL) {
252 skmem_cache_destroy(*cachep);
253 *cachep = NULL;
254 }
255 if (*usd_rp != NULL) {
256 skmem_region_release(*usd_rp);
257 *usd_rp = NULL;
258 }
259 if (*ksd_rp != NULL) {
260 skmem_region_release(*ksd_rp);
261 *ksd_rp = NULL;
262 }
263 }
264
265 static bool
skmem_arena_pp_setup(struct skmem_arena * ar,struct skmem_region_params srp[SKMEM_REGIONS],const char * name,struct kern_pbufpool * rx_pp,struct kern_pbufpool * tx_pp,boolean_t kernel_only,boolean_t pp_truncated_buf)266 skmem_arena_pp_setup(struct skmem_arena *ar,
267 struct skmem_region_params srp[SKMEM_REGIONS], const char *name,
268 struct kern_pbufpool *rx_pp, struct kern_pbufpool *tx_pp,
269 boolean_t kernel_only, boolean_t pp_truncated_buf)
270 {
271 struct skmem_arena_nexus *arn = (struct skmem_arena_nexus *)ar;
272
273 if (rx_pp == NULL && tx_pp == NULL) {
274 uint32_t ppcreatef = 0;
275 if (pp_truncated_buf) {
276 ppcreatef |= PPCREATEF_TRUNCATED_BUF;
277 }
278 if (kernel_only) {
279 ppcreatef |= PPCREATEF_KERNEL_ONLY;
280 }
281 if (srp[SKMEM_REGION_KMD].srp_max_frags > 1) {
282 ppcreatef |= PPCREATEF_ONDEMAND_BUF;
283 }
284 /* callee retains pp upon success */
285 rx_pp = pp_create(name, srp, NULL, NULL, NULL, NULL, NULL,
286 ppcreatef);
287 if (rx_pp == NULL) {
288 SK_ERR("\"%s\" ar 0x%llx flags %b failed to create pp",
289 ar->ar_name, SK_KVA(ar), ar->ar_flags, ARF_BITS);
290 return false;
291 }
292 pp_retain(rx_pp);
293 tx_pp = rx_pp;
294 } else {
295 if (rx_pp == NULL) {
296 rx_pp = tx_pp;
297 } else if (tx_pp == NULL) {
298 tx_pp = rx_pp;
299 }
300
301 ASSERT(rx_pp->pp_md_type == tx_pp->pp_md_type);
302 ASSERT(rx_pp->pp_md_subtype == tx_pp->pp_md_subtype);
303 ASSERT(!(!kernel_only &&
304 (PP_KERNEL_ONLY(rx_pp) || (PP_KERNEL_ONLY(tx_pp)))));
305 arn->arn_mode |= AR_NEXUS_MODE_EXTERNAL_PPOOL;
306 pp_retain(rx_pp);
307 pp_retain(tx_pp);
308 }
309
310 arn->arn_rx_pp = rx_pp;
311 arn->arn_tx_pp = tx_pp;
312 if (rx_pp == tx_pp) {
313 skmem_region_retain(PP_BUF_REGION_DEF(rx_pp));
314 if (PP_BUF_REGION_LARGE(rx_pp) != NULL) {
315 skmem_region_retain(PP_BUF_REGION_LARGE(rx_pp));
316 }
317 ar->ar_regions[SKMEM_REGION_BUF_DEF] = PP_BUF_REGION_DEF(rx_pp);
318 ar->ar_regions[SKMEM_REGION_BUF_LARGE] =
319 PP_BUF_REGION_LARGE(rx_pp);
320 ar->ar_regions[SKMEM_REGION_RXBUF_DEF] = NULL;
321 ar->ar_regions[SKMEM_REGION_RXBUF_LARGE] = NULL;
322 ar->ar_regions[SKMEM_REGION_TXBUF_DEF] = NULL;
323 ar->ar_regions[SKMEM_REGION_TXBUF_LARGE] = NULL;
324 skmem_region_retain(rx_pp->pp_kmd_region);
325 ar->ar_regions[SKMEM_REGION_KMD] = rx_pp->pp_kmd_region;
326 ar->ar_regions[SKMEM_REGION_RXKMD] = NULL;
327 ar->ar_regions[SKMEM_REGION_RXKMD] = NULL;
328 if (rx_pp->pp_kbft_region != NULL) {
329 skmem_region_retain(rx_pp->pp_kbft_region);
330 ar->ar_regions[SKMEM_REGION_KBFT] =
331 rx_pp->pp_kbft_region;
332 }
333 ar->ar_regions[SKMEM_REGION_RXKBFT] = NULL;
334 ar->ar_regions[SKMEM_REGION_TXKBFT] = NULL;
335 } else {
336 ASSERT(kernel_only); /* split userspace pools not supported */
337 ar->ar_regions[SKMEM_REGION_BUF_DEF] = NULL;
338 ar->ar_regions[SKMEM_REGION_BUF_LARGE] = NULL;
339 skmem_region_retain(PP_BUF_REGION_DEF(rx_pp));
340 ar->ar_regions[SKMEM_REGION_RXBUF_DEF] =
341 PP_BUF_REGION_DEF(rx_pp);
342 ar->ar_regions[SKMEM_REGION_RXBUF_LARGE] =
343 PP_BUF_REGION_LARGE(rx_pp);
344 if (PP_BUF_REGION_LARGE(rx_pp) != NULL) {
345 skmem_region_retain(PP_BUF_REGION_LARGE(rx_pp));
346 }
347 skmem_region_retain(PP_BUF_REGION_DEF(tx_pp));
348 ar->ar_regions[SKMEM_REGION_TXBUF_DEF] =
349 PP_BUF_REGION_DEF(tx_pp);
350 ar->ar_regions[SKMEM_REGION_TXBUF_LARGE] =
351 PP_BUF_REGION_LARGE(tx_pp);
352 if (PP_BUF_REGION_LARGE(tx_pp) != NULL) {
353 skmem_region_retain(PP_BUF_REGION_LARGE(tx_pp));
354 }
355 ar->ar_regions[SKMEM_REGION_KMD] = NULL;
356 skmem_region_retain(rx_pp->pp_kmd_region);
357 ar->ar_regions[SKMEM_REGION_RXKMD] = rx_pp->pp_kmd_region;
358 skmem_region_retain(tx_pp->pp_kmd_region);
359 ar->ar_regions[SKMEM_REGION_TXKMD] = tx_pp->pp_kmd_region;
360 ar->ar_regions[SKMEM_REGION_KBFT] = NULL;
361 if (rx_pp->pp_kbft_region != NULL) {
362 ASSERT(PP_HAS_BUFFER_ON_DEMAND(rx_pp));
363 skmem_region_retain(rx_pp->pp_kbft_region);
364 ar->ar_regions[SKMEM_REGION_RXKBFT] =
365 rx_pp->pp_kbft_region;
366 }
367 if (tx_pp->pp_kbft_region != NULL) {
368 ASSERT(PP_HAS_BUFFER_ON_DEMAND(tx_pp));
369 skmem_region_retain(tx_pp->pp_kbft_region);
370 ar->ar_regions[SKMEM_REGION_TXKBFT] =
371 tx_pp->pp_kbft_region;
372 }
373 }
374
375 if (kernel_only) {
376 if ((arn->arn_mode & AR_NEXUS_MODE_EXTERNAL_PPOOL) == 0) {
377 ASSERT(PP_KERNEL_ONLY(rx_pp));
378 ASSERT(PP_KERNEL_ONLY(tx_pp));
379 ASSERT(rx_pp->pp_umd_region == NULL);
380 ASSERT(tx_pp->pp_umd_region == NULL);
381 ASSERT(rx_pp->pp_kmd_region->skr_mirror == NULL);
382 ASSERT(tx_pp->pp_kmd_region->skr_mirror == NULL);
383 ASSERT(rx_pp->pp_ubft_region == NULL);
384 ASSERT(tx_pp->pp_ubft_region == NULL);
385 if (rx_pp->pp_kbft_region != NULL) {
386 ASSERT(rx_pp->pp_kbft_region->skr_mirror ==
387 NULL);
388 }
389 if (tx_pp->pp_kbft_region != NULL) {
390 ASSERT(tx_pp->pp_kbft_region->skr_mirror ==
391 NULL);
392 }
393 }
394 } else {
395 ASSERT(rx_pp == tx_pp);
396 ASSERT(!PP_KERNEL_ONLY(rx_pp));
397 ASSERT(rx_pp->pp_umd_region->skr_mode & SKR_MODE_MIRRORED);
398 ASSERT(rx_pp->pp_kmd_region->skr_mirror != NULL);
399 ar->ar_regions[SKMEM_REGION_UMD] = rx_pp->pp_umd_region;
400 skmem_region_retain(rx_pp->pp_umd_region);
401 if (rx_pp->pp_kbft_region != NULL) {
402 ASSERT(rx_pp->pp_kbft_region->skr_mirror != NULL);
403 ASSERT(rx_pp->pp_ubft_region != NULL);
404 ASSERT(rx_pp->pp_ubft_region->skr_mode &
405 SKR_MODE_MIRRORED);
406 ar->ar_regions[SKMEM_REGION_UBFT] =
407 rx_pp->pp_ubft_region;
408 skmem_region_retain(rx_pp->pp_ubft_region);
409 }
410 }
411
412 arn->arn_md_type = rx_pp->pp_md_type;
413 arn->arn_md_subtype = rx_pp->pp_md_subtype;
414 return true;
415 }
416
417 static void
skmem_arena_init_common(struct skmem_arena * ar,skmem_arena_type_t type,size_t ar_zsize,const char * ar_str,const char * name)418 skmem_arena_init_common(struct skmem_arena *ar, skmem_arena_type_t type,
419 size_t ar_zsize, const char *ar_str, const char *name)
420 {
421 ar->ar_type = type;
422 ar->ar_zsize = ar_zsize;
423 lck_mtx_init(&ar->ar_lock, &skmem_arena_lock_grp,
424 LCK_ATTR_NULL);
425 (void) snprintf(ar->ar_name, sizeof(ar->ar_name),
426 "%s.%s.%s", SKMEM_ARENA_PREFIX, ar_str, name);
427 }
428
429 /*
430 * Create a nexus adapter arena.
431 */
432 struct skmem_arena *
skmem_arena_create_for_nexus(const struct nexus_adapter * na,struct skmem_region_params srp[SKMEM_REGIONS],struct kern_pbufpool ** tx_pp,struct kern_pbufpool ** rx_pp,boolean_t pp_truncated_buf,boolean_t kernel_only,struct kern_nexus_advisory * nxv,int * perr)433 skmem_arena_create_for_nexus(const struct nexus_adapter *na,
434 struct skmem_region_params srp[SKMEM_REGIONS], struct kern_pbufpool **tx_pp,
435 struct kern_pbufpool **rx_pp, boolean_t pp_truncated_buf,
436 boolean_t kernel_only, struct kern_nexus_advisory *nxv, int *perr)
437 {
438 #define SRP_CFLAGS(_id) (srp[_id].srp_cflags)
439 struct skmem_arena *ar;
440 struct skmem_arena_nexus *__single arn;
441 char cname[64];
442 uint32_t i;
443 const char *__null_terminated name =
444 __unsafe_null_terminated_from_indexable(na->na_name);
445 uint32_t msize = 0;
446 void *__sized_by(msize) maddr = NULL;
447
448 *perr = 0;
449
450 arn = zalloc_flags(ar_nexus_zone, Z_WAITOK | Z_ZERO | Z_NOFAIL);
451 ar = &arn->arn_cmn;
452 skmem_arena_init_common(ar, SKMEM_ARENA_TYPE_NEXUS, AR_NEXUS_SIZE,
453 "nexus", name);
454
455 ASSERT(ar != NULL && ar->ar_zsize == AR_NEXUS_SIZE);
456
457 /* these regions must not be readable/writeable */
458 ASSERT(SRP_CFLAGS(SKMEM_REGION_GUARD_HEAD) & SKMEM_REGION_CR_GUARD);
459 ASSERT(SRP_CFLAGS(SKMEM_REGION_GUARD_TAIL) & SKMEM_REGION_CR_GUARD);
460
461 /* these regions must be read-only */
462 ASSERT(SRP_CFLAGS(SKMEM_REGION_SCHEMA) & SKMEM_REGION_CR_UREADONLY);
463 ASSERT(SRP_CFLAGS(SKMEM_REGION_FLOWADV) & SKMEM_REGION_CR_UREADONLY);
464 ASSERT(SRP_CFLAGS(SKMEM_REGION_NEXUSADV) & SKMEM_REGION_CR_UREADONLY);
465 if ((na->na_flags & NAF_USER_PKT_POOL) == 0) {
466 ASSERT(SRP_CFLAGS(SKMEM_REGION_TXAUSD) &
467 SKMEM_REGION_CR_UREADONLY);
468 ASSERT(SRP_CFLAGS(SKMEM_REGION_RXFUSD) &
469 SKMEM_REGION_CR_UREADONLY);
470 } else {
471 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_TXAUSD) &
472 SKMEM_REGION_CR_UREADONLY));
473 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_RXFUSD) &
474 SKMEM_REGION_CR_UREADONLY));
475 }
476
477 /* these regions must be user-mappable */
478 ASSERT(SRP_CFLAGS(SKMEM_REGION_GUARD_HEAD) & SKMEM_REGION_CR_MMAPOK);
479 ASSERT(SRP_CFLAGS(SKMEM_REGION_SCHEMA) & SKMEM_REGION_CR_MMAPOK);
480 ASSERT(SRP_CFLAGS(SKMEM_REGION_RING) & SKMEM_REGION_CR_MMAPOK);
481 ASSERT(SRP_CFLAGS(SKMEM_REGION_BUF_DEF) & SKMEM_REGION_CR_MMAPOK);
482 ASSERT(SRP_CFLAGS(SKMEM_REGION_BUF_LARGE) & SKMEM_REGION_CR_MMAPOK);
483 ASSERT(SRP_CFLAGS(SKMEM_REGION_UMD) & SKMEM_REGION_CR_MMAPOK);
484 ASSERT(SRP_CFLAGS(SKMEM_REGION_UBFT) & SKMEM_REGION_CR_MMAPOK);
485 ASSERT(SRP_CFLAGS(SKMEM_REGION_TXAUSD) & SKMEM_REGION_CR_MMAPOK);
486 ASSERT(SRP_CFLAGS(SKMEM_REGION_RXFUSD) & SKMEM_REGION_CR_MMAPOK);
487 ASSERT(SRP_CFLAGS(SKMEM_REGION_USTATS) & SKMEM_REGION_CR_MMAPOK);
488 ASSERT(SRP_CFLAGS(SKMEM_REGION_FLOWADV) & SKMEM_REGION_CR_MMAPOK);
489 ASSERT(SRP_CFLAGS(SKMEM_REGION_NEXUSADV) & SKMEM_REGION_CR_MMAPOK);
490 ASSERT(SRP_CFLAGS(SKMEM_REGION_GUARD_TAIL) & SKMEM_REGION_CR_MMAPOK);
491
492 /* these must not be user-mappable */
493 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_KMD) & SKMEM_REGION_CR_MMAPOK));
494 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_RXKMD) & SKMEM_REGION_CR_MMAPOK));
495 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_TXKMD) & SKMEM_REGION_CR_MMAPOK));
496 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_KBFT) & SKMEM_REGION_CR_MMAPOK));
497 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_RXKBFT) & SKMEM_REGION_CR_MMAPOK));
498 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_TXKBFT) & SKMEM_REGION_CR_MMAPOK));
499 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_TXAKSD) & SKMEM_REGION_CR_MMAPOK));
500 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_RXFKSD) & SKMEM_REGION_CR_MMAPOK));
501 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_KSTATS) & SKMEM_REGION_CR_MMAPOK));
502
503 /* these regions must be shareable */
504 ASSERT(SRP_CFLAGS(SKMEM_REGION_BUF_DEF) & SKMEM_REGION_CR_SHAREOK);
505 ASSERT(SRP_CFLAGS(SKMEM_REGION_BUF_LARGE) & SKMEM_REGION_CR_SHAREOK);
506 ASSERT(SRP_CFLAGS(SKMEM_REGION_RXBUF_DEF) & SKMEM_REGION_CR_SHAREOK);
507 ASSERT(SRP_CFLAGS(SKMEM_REGION_RXBUF_LARGE) & SKMEM_REGION_CR_SHAREOK);
508 ASSERT(SRP_CFLAGS(SKMEM_REGION_TXBUF_DEF) & SKMEM_REGION_CR_SHAREOK);
509 ASSERT(SRP_CFLAGS(SKMEM_REGION_TXBUF_LARGE) & SKMEM_REGION_CR_SHAREOK);
510
511 /* these regions must not be be shareable */
512 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_GUARD_HEAD) & SKMEM_REGION_CR_SHAREOK));
513 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_SCHEMA) & SKMEM_REGION_CR_SHAREOK));
514 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_RING) & SKMEM_REGION_CR_SHAREOK));
515 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_UMD) & SKMEM_REGION_CR_SHAREOK));
516 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_UBFT) & SKMEM_REGION_CR_SHAREOK));
517 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_TXAUSD) & SKMEM_REGION_CR_SHAREOK));
518 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_RXFUSD) & SKMEM_REGION_CR_SHAREOK));
519 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_USTATS) & SKMEM_REGION_CR_SHAREOK));
520 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_FLOWADV) & SKMEM_REGION_CR_SHAREOK));
521 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_NEXUSADV) & SKMEM_REGION_CR_SHAREOK));
522 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_GUARD_TAIL) & SKMEM_REGION_CR_SHAREOK));
523 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_KMD) & SKMEM_REGION_CR_SHAREOK));
524 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_RXKMD) & SKMEM_REGION_CR_SHAREOK));
525 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_TXKMD) & SKMEM_REGION_CR_SHAREOK));
526 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_KBFT) & SKMEM_REGION_CR_SHAREOK));
527 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_RXKBFT) & SKMEM_REGION_CR_SHAREOK));
528 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_TXKBFT) & SKMEM_REGION_CR_SHAREOK));
529 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_TXAKSD) & SKMEM_REGION_CR_SHAREOK));
530 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_RXFKSD) & SKMEM_REGION_CR_SHAREOK));
531 ASSERT(!(SRP_CFLAGS(SKMEM_REGION_KSTATS) & SKMEM_REGION_CR_SHAREOK));
532
533 /* these must stay active */
534 ASSERT(SRP_CFLAGS(SKMEM_REGION_GUARD_HEAD) & SKMEM_REGION_CR_NOREDIRECT);
535 ASSERT(SRP_CFLAGS(SKMEM_REGION_SCHEMA) & SKMEM_REGION_CR_NOREDIRECT);
536 ASSERT(SRP_CFLAGS(SKMEM_REGION_GUARD_TAIL) & SKMEM_REGION_CR_NOREDIRECT);
537
538 /* no kstats for nexus */
539 ASSERT(srp[SKMEM_REGION_KSTATS].srp_c_obj_cnt == 0);
540
541 AR_LOCK(ar);
542 if (!skmem_arena_pp_setup(ar, srp, name, (rx_pp ? *rx_pp : NULL),
543 (tx_pp ? *tx_pp : NULL), kernel_only, pp_truncated_buf)) {
544 goto failed;
545 }
546
547 if (nxv != NULL && nxv->nxv_reg != NULL) {
548 struct skmem_region *skr = nxv->nxv_reg;
549
550 ASSERT(skr->skr_cflags & SKMEM_REGION_CR_MONOLITHIC);
551 ASSERT(skr->skr_seg_max_cnt == 1);
552 ar->ar_regions[SKMEM_REGION_NEXUSADV] = skr;
553 skmem_region_retain(skr);
554
555 ASSERT(nxv->nxv_adv != NULL);
556 if (nxv->nxv_adv_type == NEXUS_ADVISORY_TYPE_FLOWSWITCH) {
557 VERIFY(nxv->flowswitch_nxv_adv->nxadv_ver ==
558 NX_FLOWSWITCH_ADVISORY_CURRENT_VERSION);
559 } else if (nxv->nxv_adv_type == NEXUS_ADVISORY_TYPE_NETIF) {
560 VERIFY(nxv->netif_nxv_adv->nna_version ==
561 NX_NETIF_ADVISORY_CURRENT_VERSION);
562 } else {
563 panic_plain("%s: invalid advisory type %d",
564 __func__, nxv->nxv_adv_type);
565 /* NOTREACHED */
566 }
567 arn->arn_nexusadv_obj = nxv->nxv_adv;
568 } else {
569 ASSERT(ar->ar_regions[SKMEM_REGION_NEXUSADV] == NULL);
570 ASSERT(srp[SKMEM_REGION_NEXUSADV].srp_c_obj_cnt == 0);
571 }
572
573 if (skmem_arena_sd_setup(na, srp, ar, kernel_only, TRUE) != 0) {
574 goto failed;
575 }
576
577 if (skmem_arena_sd_setup(na, srp, ar, kernel_only, FALSE) != 0) {
578 goto failed;
579 }
580
581 for (i = 0; i < SKMEM_REGIONS; i++) {
582 /* skip if already created */
583 if (ar->ar_regions[i] != NULL) {
584 continue;
585 }
586
587 /* skip external regions from packet pool */
588 if (skmem_region_for_pp(i)) {
589 continue;
590 }
591
592 /* skip slot descriptor regions */
593 if (i == SKMEM_REGION_TXAUSD || i == SKMEM_REGION_RXFUSD ||
594 i == SKMEM_REGION_TXAKSD || i == SKMEM_REGION_RXFKSD) {
595 continue;
596 }
597
598 /* skip if region is configured to be empty */
599 if (srp[i].srp_c_obj_cnt == 0) {
600 ASSERT(i == SKMEM_REGION_GUARD_HEAD ||
601 i == SKMEM_REGION_USTATS ||
602 i == SKMEM_REGION_KSTATS ||
603 i == SKMEM_REGION_INTRINSIC ||
604 i == SKMEM_REGION_FLOWADV ||
605 i == SKMEM_REGION_NEXUSADV ||
606 i == SKMEM_REGION_SYSCTLS ||
607 i == SKMEM_REGION_GUARD_TAIL);
608 continue;
609 }
610
611 ASSERT(srp[i].srp_id == i);
612
613 /*
614 * Skip {SCHEMA, RING, GUARD} for kernel-only arena. Note
615 * that this is assuming kernel-only arena is always used
616 * for kernel-only nexus adapters (never used directly by
617 * user process.)
618 *
619 * XXX [email protected] - see comments in kern_pbufpool_create().
620 * We need to revisit this logic for "direct channel" access,
621 * perhaps via a separate adapter flag.
622 */
623 if (kernel_only && (i == SKMEM_REGION_GUARD_HEAD ||
624 i == SKMEM_REGION_SCHEMA || i == SKMEM_REGION_RING ||
625 i == SKMEM_REGION_GUARD_TAIL)) {
626 continue;
627 }
628
629 /* not for nexus, or for us to create here */
630 ASSERT(i != SKMEM_REGION_GUARD_HEAD || sk_guard);
631 ASSERT(i != SKMEM_REGION_NEXUSADV);
632 ASSERT(i != SKMEM_REGION_SYSCTLS);
633 ASSERT(i != SKMEM_REGION_GUARD_TAIL || sk_guard);
634 ASSERT(i != SKMEM_REGION_KSTATS);
635 ASSERT(i != SKMEM_REGION_INTRINSIC);
636
637 /* otherwise create it */
638 if ((ar->ar_regions[i] = skmem_region_create(name, &srp[i],
639 NULL, NULL, NULL)) == NULL) {
640 SK_ERR("\"%s\" ar 0x%llx flags %b failed to "
641 "create %s region", ar->ar_name, SK_KVA(ar),
642 ar->ar_flags, ARF_BITS, srp[i].srp_name);
643 goto failed;
644 }
645 }
646
647 /* create skmem_cache for schema (without magazines) */
648 ASSERT(ar->ar_regions[SKMEM_REGION_SCHEMA] != NULL || kernel_only);
649 if (ar->ar_regions[SKMEM_REGION_SCHEMA] != NULL) {
650 name = tsnprintf(cname, sizeof(cname), "schema.%.*s",
651 (int)sizeof(na->na_name), na->na_name);
652 if ((arn->arn_schema_cache = skmem_cache_create(name,
653 srp[SKMEM_REGION_SCHEMA].srp_c_obj_size, 0, NULL,
654 NULL, NULL, NULL, ar->ar_regions[SKMEM_REGION_SCHEMA],
655 SKMEM_CR_NOMAGAZINES)) == NULL) {
656 SK_ERR("\"%s\" ar 0x%llx flags %b failed to create %s",
657 ar->ar_name, SK_KVA(ar), ar->ar_flags, ARF_BITS,
658 cname);
659 goto failed;
660 }
661 }
662
663 /* create skmem_cache for rings (without magazines) */
664 name = tsnprintf(cname, sizeof(cname), "ring.%.*s",
665 (int)sizeof(na->na_name), na->na_name);
666 ASSERT(ar->ar_regions[SKMEM_REGION_RING] != NULL || kernel_only);
667 if ((ar->ar_regions[SKMEM_REGION_RING] != NULL) &&
668 (arn->arn_ring_cache = skmem_cache_create(name,
669 srp[SKMEM_REGION_RING].srp_c_obj_size, 0, NULL, NULL, NULL,
670 NULL, ar->ar_regions[SKMEM_REGION_RING],
671 SKMEM_CR_NOMAGAZINES)) == NULL) {
672 SK_ERR("\"%s\" ar 0x%llx flags %b failed to create %s",
673 ar->ar_name, SK_KVA(ar), ar->ar_flags, ARF_BITS, cname);
674 goto failed;
675 }
676
677 /*
678 * If the stats region is present, allocate a single object directly
679 * from the region; we don't need to create an skmem_cache for this,
680 * as the object is allocated (and freed) only once.
681 */
682 if (ar->ar_regions[SKMEM_REGION_USTATS] != NULL) {
683 struct skmem_region *skr = ar->ar_regions[SKMEM_REGION_USTATS];
684 void *obj;
685
686 /* no kstats for nexus */
687 ASSERT(ar->ar_regions[SKMEM_REGION_KSTATS] == NULL);
688 ASSERT(skr->skr_cflags & SKMEM_REGION_CR_MONOLITHIC);
689 ASSERT(skr->skr_seg_max_cnt == 1);
690
691 if ((obj = skmem_region_alloc(skr, &maddr,
692 NULL, NULL, SKMEM_SLEEP, skr->skr_c_obj_size, &msize)) == NULL) {
693 SK_ERR("\"%s\" ar 0x%llx flags %b failed to alloc "
694 "stats", ar->ar_name, SK_KVA(ar), ar->ar_flags,
695 ARF_BITS);
696 goto failed;
697 }
698 arn->arn_stats_obj = obj;
699 arn->arn_stats_obj_size = skr->skr_c_obj_size;
700 }
701 ASSERT(ar->ar_regions[SKMEM_REGION_KSTATS] == NULL);
702
703 /*
704 * If the flowadv region is present, allocate a single object directly
705 * from the region; we don't need to create an skmem_cache for this,
706 * as the object is allocated (and freed) only once.
707 */
708 if (ar->ar_regions[SKMEM_REGION_FLOWADV] != NULL) {
709 struct skmem_region *skr =
710 ar->ar_regions[SKMEM_REGION_FLOWADV];
711 void *obj;
712
713 ASSERT(skr->skr_cflags & SKMEM_REGION_CR_MONOLITHIC);
714 ASSERT(skr->skr_seg_max_cnt == 1);
715
716 if ((obj = skmem_region_alloc(skr, &maddr,
717 NULL, NULL, SKMEM_SLEEP, skr->skr_c_obj_size, &msize)) == NULL) {
718 SK_ERR("\"%s\" ar 0x%llx flags %b failed to alloc "
719 "flowadv", ar->ar_name, SK_KVA(ar), ar->ar_flags,
720 ARF_BITS);
721 goto failed;
722 }
723 /* XXX -fbounds-safety: should get the count elsewhere */
724 arn->arn_flowadv_obj = obj;
725 arn->arn_flowadv_entries = sk_max_flows;
726 }
727
728 if (skmem_arena_create_finalize(ar) != 0) {
729 SK_ERR("\"%s\" ar 0x%llx flags %b failed to finalize",
730 ar->ar_name, SK_KVA(ar), ar->ar_flags, ARF_BITS);
731 goto failed;
732 }
733
734 ++ar->ar_refcnt; /* for caller */
735 AR_UNLOCK(ar);
736
737 SKMEM_ARENA_LOCK();
738 TAILQ_INSERT_TAIL(&skmem_arena_head, ar, ar_link);
739 SKMEM_ARENA_UNLOCK();
740
741 /* caller didn't give us one, but would like us to return it? */
742 if (rx_pp != NULL && *rx_pp == NULL) {
743 *rx_pp = arn->arn_rx_pp;
744 pp_retain(*rx_pp);
745 }
746 if (tx_pp != NULL && *tx_pp == NULL) {
747 *tx_pp = arn->arn_tx_pp;
748 pp_retain(*tx_pp); /* for caller */
749 }
750
751 #if SK_LOG
752 if (__improbable(sk_verbose != 0)) {
753 skmem_arena_create_region_log(ar);
754 }
755 #endif /* SK_LOG */
756
757 return ar;
758
759 failed:
760 AR_LOCK_ASSERT_HELD(ar);
761 skmem_arena_destroy(ar);
762 *perr = ENOMEM;
763
764 return NULL;
765 #undef SRP_CFLAGS
766 }
767
768 void
skmem_arena_nexus_sd_set_noidle(struct skmem_arena_nexus * arn,int cnt)769 skmem_arena_nexus_sd_set_noidle(struct skmem_arena_nexus *arn, int cnt)
770 {
771 struct skmem_arena *ar = &arn->arn_cmn;
772
773 AR_LOCK(ar);
774 arn->arn_ksd_nodefunct += cnt;
775 VERIFY(arn->arn_ksd_nodefunct >= 0);
776 AR_UNLOCK(ar);
777 }
778
779 boolean_t
skmem_arena_nexus_sd_idle(struct skmem_arena_nexus * arn)780 skmem_arena_nexus_sd_idle(struct skmem_arena_nexus *arn)
781 {
782 struct skmem_arena *ar = &arn->arn_cmn;
783 boolean_t idle;
784
785 AR_LOCK(ar);
786 VERIFY(arn->arn_ksd_nodefunct >= 0);
787 idle = (arn->arn_ksd_nodefunct == 0);
788 AR_UNLOCK(ar);
789
790 return idle;
791 }
792
793 static void
skmem_arena_nexus_teardown(struct skmem_arena_nexus * arn,boolean_t defunct)794 skmem_arena_nexus_teardown(struct skmem_arena_nexus *arn, boolean_t defunct)
795 {
796 struct skmem_arena *ar = &arn->arn_cmn;
797 struct skmem_region *skr;
798 int i;
799
800 AR_LOCK_ASSERT_HELD(ar);
801 ASSERT(ar->ar_type == SKMEM_ARENA_TYPE_NEXUS);
802
803 /* these should never be set for nexus arena */
804 ASSERT(ar->ar_regions[SKMEM_REGION_GUARD_HEAD] == NULL || sk_guard);
805 ASSERT(ar->ar_regions[SKMEM_REGION_SYSCTLS] == NULL);
806 ASSERT(ar->ar_regions[SKMEM_REGION_GUARD_TAIL] == NULL || sk_guard);
807 ASSERT(ar->ar_regions[SKMEM_REGION_KSTATS] == NULL);
808 ASSERT(ar->ar_regions[SKMEM_REGION_INTRINSIC] == NULL);
809
810 if (arn->arn_stats_obj != NULL) {
811 skr = ar->ar_regions[SKMEM_REGION_USTATS];
812 ASSERT(skr != NULL && !(skr->skr_mode & SKR_MODE_NOREDIRECT));
813 skmem_region_free(skr, arn->arn_stats_obj, NULL);
814 arn->arn_stats_obj_size = 0;
815 arn->arn_stats_obj = NULL;
816 skmem_region_release(skr);
817 ar->ar_regions[SKMEM_REGION_USTATS] = NULL;
818 }
819 ASSERT(ar->ar_regions[SKMEM_REGION_USTATS] == NULL);
820 ASSERT(arn->arn_stats_obj == NULL);
821
822 if (arn->arn_flowadv_obj != NULL) {
823 skr = ar->ar_regions[SKMEM_REGION_FLOWADV];
824 ASSERT(skr != NULL && !(skr->skr_mode & SKR_MODE_NOREDIRECT));
825
826 /* XXX -fbounds-safety */
827 void *obj = __unsafe_forge_bidi_indexable(void *,
828 arn->arn_flowadv_obj, skr->skr_c_obj_size);
829 skmem_region_free(skr, obj, NULL);
830 arn->arn_flowadv_obj = NULL;
831 arn->arn_flowadv_entries = 0;
832 skmem_region_release(skr);
833 ar->ar_regions[SKMEM_REGION_FLOWADV] = NULL;
834 }
835 ASSERT(ar->ar_regions[SKMEM_REGION_FLOWADV] == NULL);
836 ASSERT(arn->arn_flowadv_obj == NULL);
837
838 if (arn->arn_nexusadv_obj != NULL) {
839 skr = ar->ar_regions[SKMEM_REGION_NEXUSADV];
840 ASSERT(skr != NULL && !(skr->skr_mode & SKR_MODE_NOREDIRECT));
841 /* we didn't allocate this, so just nullify it */
842 arn->arn_nexusadv_obj = NULL;
843 skmem_region_release(skr);
844 ar->ar_regions[SKMEM_REGION_NEXUSADV] = NULL;
845 }
846 ASSERT(ar->ar_regions[SKMEM_REGION_NEXUSADV] == NULL);
847 ASSERT(arn->arn_nexusadv_obj == NULL);
848
849 ASSERT(!((arn->arn_rx_pp == NULL) ^ (arn->arn_tx_pp == NULL)));
850 if (arn->arn_rx_pp != NULL) {
851 for (i = 0; i < SKMEM_PP_REGIONS; i++) {
852 skmem_region_id_t reg = skmem_pp_region_ids[i];
853 skr = ar->ar_regions[reg];
854 if (skr != NULL) {
855 ASSERT(!(skr->skr_mode & SKR_MODE_NOREDIRECT));
856 skmem_region_release(skr);
857 ar->ar_regions[reg] = NULL;
858 }
859 }
860 pp_release(arn->arn_rx_pp);
861 pp_release(arn->arn_tx_pp);
862 arn->arn_rx_pp = NULL;
863 arn->arn_tx_pp = NULL;
864 }
865 for (i = 0; i < SKMEM_PP_REGIONS; i++) {
866 ASSERT(ar->ar_regions[skmem_pp_region_ids[i]] == NULL);
867 }
868 ASSERT(arn->arn_rx_pp == NULL);
869 ASSERT(arn->arn_tx_pp == NULL);
870
871 if (arn->arn_ring_cache != NULL) {
872 skr = ar->ar_regions[SKMEM_REGION_RING];
873 ASSERT(skr != NULL && !(skr->skr_mode & SKR_MODE_NOREDIRECT));
874 skmem_cache_destroy(arn->arn_ring_cache);
875 arn->arn_ring_cache = NULL;
876 skmem_region_release(skr);
877 ar->ar_regions[SKMEM_REGION_RING] = NULL;
878 }
879 ASSERT(ar->ar_regions[SKMEM_REGION_RING] == NULL);
880 ASSERT(arn->arn_ring_cache == NULL);
881
882 /*
883 * Stop here if we're in the defunct context, and we're asked
884 * to keep the slot descriptor regions alive as they are still
885 * being referred to by the nexus owner (driver).
886 */
887 if (defunct && arn->arn_ksd_nodefunct != 0) {
888 ASSERT(arn->arn_ksd_nodefunct > 0);
889 return;
890 }
891
892 ASSERT(arn->arn_ksd_nodefunct == 0);
893 skmem_arena_sd_teardown(ar, TRUE);
894 skmem_arena_sd_teardown(ar, FALSE);
895
896 /* stop here if we're in the defunct context */
897 if (defunct) {
898 return;
899 }
900 if (arn->arn_schema_cache != NULL) {
901 skr = ar->ar_regions[SKMEM_REGION_SCHEMA];
902 ASSERT(skr != NULL && (skr->skr_mode & SKR_MODE_NOREDIRECT));
903 skmem_cache_destroy(arn->arn_schema_cache);
904 arn->arn_schema_cache = NULL;
905 skmem_region_release(skr);
906 ar->ar_regions[SKMEM_REGION_SCHEMA] = NULL;
907 }
908 ASSERT(ar->ar_regions[SKMEM_REGION_SCHEMA] == NULL);
909 ASSERT(arn->arn_schema_cache == NULL);
910
911 if ((skr = ar->ar_regions[SKMEM_REGION_GUARD_HEAD]) != NULL) {
912 ASSERT(skr->skr_mode & SKR_MODE_NOREDIRECT);
913 skmem_region_release(skr);
914 ar->ar_regions[SKMEM_REGION_GUARD_HEAD] = NULL;
915 }
916 ASSERT(ar->ar_regions[SKMEM_REGION_GUARD_HEAD] == NULL);
917 if ((skr = ar->ar_regions[SKMEM_REGION_GUARD_TAIL]) != NULL) {
918 ASSERT(skr->skr_mode & SKR_MODE_NOREDIRECT);
919 skmem_region_release(skr);
920 ar->ar_regions[SKMEM_REGION_GUARD_TAIL] = NULL;
921 }
922 ASSERT(ar->ar_regions[SKMEM_REGION_GUARD_TAIL] == NULL);
923 }
924
925 /*
926 * Create an NECP arena.
927 */
928 struct skmem_arena *
skmem_arena_create_for_necp(const char * name,struct skmem_region_params * srp_ustats,struct skmem_region_params * srp_kstats,int * perr)929 skmem_arena_create_for_necp(const char *name,
930 struct skmem_region_params *srp_ustats,
931 struct skmem_region_params *srp_kstats, int *perr)
932 {
933 struct skmem_arena_necp *__single arc;
934 struct skmem_arena *ar;
935 char cname[64];
936 const char *__null_terminated cache_name = NULL;
937
938 *perr = 0;
939
940 arc = zalloc_flags(ar_necp_zone, Z_WAITOK | Z_ZERO | Z_NOFAIL);
941 ar = &arc->arc_cmn;
942 skmem_arena_init_common(ar, SKMEM_ARENA_TYPE_NECP, AR_NECP_SIZE,
943 "necp", name);
944
945 ASSERT(ar != NULL && ar->ar_zsize == AR_NECP_SIZE);
946
947 /*
948 * Must be stats region, and must be user-mappable;
949 * don't assert for SKMEM_REGION_CR_MONOLITHIC here
950 * as the client might want multi-segment mode.
951 */
952 ASSERT(srp_ustats->srp_id == SKMEM_REGION_USTATS);
953 ASSERT(srp_kstats->srp_id == SKMEM_REGION_KSTATS);
954 ASSERT(srp_ustats->srp_cflags & SKMEM_REGION_CR_MMAPOK);
955 ASSERT(!(srp_kstats->srp_cflags & SKMEM_REGION_CR_MMAPOK));
956 ASSERT(!(srp_ustats->srp_cflags & SKMEM_REGION_CR_SHAREOK));
957 ASSERT(!(srp_kstats->srp_cflags & SKMEM_REGION_CR_SHAREOK));
958 ASSERT(srp_ustats->srp_c_obj_size != 0);
959 ASSERT(srp_kstats->srp_c_obj_size != 0);
960 ASSERT(srp_ustats->srp_c_obj_cnt != 0);
961 ASSERT(srp_kstats->srp_c_obj_cnt != 0);
962 ASSERT(srp_ustats->srp_c_seg_size == srp_kstats->srp_c_seg_size);
963 ASSERT(srp_ustats->srp_seg_cnt == srp_kstats->srp_seg_cnt);
964 ASSERT(srp_ustats->srp_c_obj_size == srp_kstats->srp_c_obj_size);
965 ASSERT(srp_ustats->srp_c_obj_cnt == srp_kstats->srp_c_obj_cnt);
966
967 AR_LOCK(ar);
968
969 if ((ar->ar_regions[SKMEM_REGION_USTATS] = skmem_region_create(name,
970 srp_ustats, NULL, NULL, NULL)) == NULL) {
971 SK_ERR("\"%s\" ar 0x%llx flags %b failed to create %s region",
972 ar->ar_name, SK_KVA(ar), ar->ar_flags, ARF_BITS,
973 srp_ustats->srp_name);
974 goto failed;
975 }
976
977 if ((ar->ar_regions[SKMEM_REGION_KSTATS] = skmem_region_create(name,
978 srp_kstats, NULL, NULL, NULL)) == NULL) {
979 SK_ERR("\"%s\" ar 0x%llx flags %b failed to create %s region",
980 ar->ar_name, SK_KVA(ar), ar->ar_flags, ARF_BITS,
981 srp_kstats->srp_name);
982 goto failed;
983 }
984
985 skmem_region_mirror(ar->ar_regions[SKMEM_REGION_KSTATS],
986 ar->ar_regions[SKMEM_REGION_USTATS]);
987
988 /* create skmem_cache for kernel stats (without magazines) */
989 cache_name = tsnprintf(cname, sizeof(cname), "kstats.%s", name);
990 if ((arc->arc_kstats_cache = skmem_cache_create(cache_name,
991 srp_kstats->srp_c_obj_size, 0, necp_stats_ctor, NULL, NULL,
992 NULL, ar->ar_regions[SKMEM_REGION_KSTATS],
993 SKMEM_CR_NOMAGAZINES)) == NULL) {
994 SK_ERR("\"%s\" ar 0x%llx flags %b failed to create %s",
995 ar->ar_name, SK_KVA(ar), ar->ar_flags, ARF_BITS, cname);
996 goto failed;
997 }
998
999 if (skmem_arena_create_finalize(ar) != 0) {
1000 SK_ERR("\"%s\" ar 0x%llx flags %b failed to finalize",
1001 ar->ar_name, SK_KVA(ar), ar->ar_flags, ARF_BITS);
1002 goto failed;
1003 }
1004
1005 /*
1006 * These must never be configured for NECP arena.
1007 *
1008 * XXX: In theory we can add guard pages to this arena,
1009 * but for now leave that as an exercise for the future.
1010 */
1011 ASSERT(ar->ar_regions[SKMEM_REGION_GUARD_HEAD] == NULL);
1012 ASSERT(ar->ar_regions[SKMEM_REGION_SCHEMA] == NULL);
1013 ASSERT(ar->ar_regions[SKMEM_REGION_RING] == NULL);
1014 ASSERT(ar->ar_regions[SKMEM_REGION_TXAUSD] == NULL);
1015 ASSERT(ar->ar_regions[SKMEM_REGION_RXFUSD] == NULL);
1016 ASSERT(ar->ar_regions[SKMEM_REGION_FLOWADV] == NULL);
1017 ASSERT(ar->ar_regions[SKMEM_REGION_NEXUSADV] == NULL);
1018 ASSERT(ar->ar_regions[SKMEM_REGION_SYSCTLS] == NULL);
1019 ASSERT(ar->ar_regions[SKMEM_REGION_GUARD_TAIL] == NULL);
1020 ASSERT(ar->ar_regions[SKMEM_REGION_TXAKSD] == NULL);
1021 ASSERT(ar->ar_regions[SKMEM_REGION_RXFKSD] == NULL);
1022 ASSERT(ar->ar_regions[SKMEM_REGION_INTRINSIC] == NULL);
1023 for (int i = 0; i < SKMEM_PP_REGIONS; i++) {
1024 ASSERT(ar->ar_regions[skmem_pp_region_ids[i]] == NULL);
1025 }
1026
1027 /* these must be configured for NECP arena */
1028 ASSERT(ar->ar_regions[SKMEM_REGION_USTATS] != NULL);
1029 ASSERT(ar->ar_regions[SKMEM_REGION_KSTATS] != NULL);
1030
1031 ++ar->ar_refcnt; /* for caller */
1032 AR_UNLOCK(ar);
1033
1034 SKMEM_ARENA_LOCK();
1035 TAILQ_INSERT_TAIL(&skmem_arena_head, ar, ar_link);
1036 SKMEM_ARENA_UNLOCK();
1037
1038 #if SK_LOG
1039 if (__improbable(sk_verbose != 0)) {
1040 skmem_arena_create_region_log(ar);
1041 }
1042 #endif /* SK_LOG */
1043
1044 return ar;
1045
1046 failed:
1047 AR_LOCK_ASSERT_HELD(ar);
1048 skmem_arena_destroy(ar);
1049 *perr = ENOMEM;
1050
1051 return NULL;
1052 }
1053
1054 static void
skmem_arena_necp_teardown(struct skmem_arena_necp * arc,boolean_t defunct)1055 skmem_arena_necp_teardown(struct skmem_arena_necp *arc, boolean_t defunct)
1056 {
1057 #pragma unused(defunct)
1058 struct skmem_arena *ar = &arc->arc_cmn;
1059 struct skmem_region *skr;
1060
1061 AR_LOCK_ASSERT_HELD(ar);
1062 ASSERT(ar->ar_type == SKMEM_ARENA_TYPE_NECP);
1063
1064 /* these must never be configured for NECP arena */
1065 ASSERT(ar->ar_regions[SKMEM_REGION_GUARD_HEAD] == NULL);
1066 ASSERT(ar->ar_regions[SKMEM_REGION_SCHEMA] == NULL);
1067 ASSERT(ar->ar_regions[SKMEM_REGION_RING] == NULL);
1068 ASSERT(ar->ar_regions[SKMEM_REGION_TXAUSD] == NULL);
1069 ASSERT(ar->ar_regions[SKMEM_REGION_RXFUSD] == NULL);
1070 ASSERT(ar->ar_regions[SKMEM_REGION_FLOWADV] == NULL);
1071 ASSERT(ar->ar_regions[SKMEM_REGION_NEXUSADV] == NULL);
1072 ASSERT(ar->ar_regions[SKMEM_REGION_SYSCTLS] == NULL);
1073 ASSERT(ar->ar_regions[SKMEM_REGION_GUARD_TAIL] == NULL);
1074 ASSERT(ar->ar_regions[SKMEM_REGION_TXAKSD] == NULL);
1075 ASSERT(ar->ar_regions[SKMEM_REGION_RXFKSD] == NULL);
1076 ASSERT(ar->ar_regions[SKMEM_REGION_INTRINSIC] == NULL);
1077 for (int i = 0; i < SKMEM_PP_REGIONS; i++) {
1078 ASSERT(ar->ar_regions[skmem_pp_region_ids[i]] == NULL);
1079 }
1080
1081 if (arc->arc_kstats_cache != NULL) {
1082 skr = ar->ar_regions[SKMEM_REGION_KSTATS];
1083 ASSERT(skr != NULL && !(skr->skr_mode & SKR_MODE_NOREDIRECT));
1084 skmem_cache_destroy(arc->arc_kstats_cache);
1085 arc->arc_kstats_cache = NULL;
1086 skmem_region_release(skr);
1087 ar->ar_regions[SKMEM_REGION_KSTATS] = NULL;
1088
1089 skr = ar->ar_regions[SKMEM_REGION_USTATS];
1090 ASSERT(skr != NULL && !(skr->skr_mode & SKR_MODE_NOREDIRECT));
1091 skmem_region_release(skr);
1092 ar->ar_regions[SKMEM_REGION_USTATS] = NULL;
1093 }
1094 ASSERT(ar->ar_regions[SKMEM_REGION_USTATS] == NULL);
1095 ASSERT(ar->ar_regions[SKMEM_REGION_KSTATS] == NULL);
1096 ASSERT(arc->arc_kstats_cache == NULL);
1097 }
1098
1099 /*
1100 * Given an arena, return its NECP variant (if applicable).
1101 */
1102 struct skmem_arena_necp *
skmem_arena_necp(struct skmem_arena * ar)1103 skmem_arena_necp(struct skmem_arena *ar)
1104 {
1105 if (__improbable(ar->ar_type != SKMEM_ARENA_TYPE_NECP)) {
1106 return NULL;
1107 }
1108
1109 return (struct skmem_arena_necp *)ar;
1110 }
1111
1112 /*
1113 * Create a System arena.
1114 */
1115 struct skmem_arena *
skmem_arena_create_for_system(const char * name,int * perr)1116 skmem_arena_create_for_system(const char *name, int *perr)
1117 {
1118 struct skmem_region *skrsys;
1119 struct skmem_arena_system *ars;
1120 struct skmem_arena *ar;
1121
1122 *perr = 0;
1123
1124 ars = zalloc_flags(ar_system_zone, Z_WAITOK | Z_ZERO | Z_NOFAIL);
1125 ar = &ars->ars_cmn;
1126 skmem_arena_init_common(ar, SKMEM_ARENA_TYPE_SYSTEM, AR_SYSTEM_SIZE,
1127 "system", name);
1128
1129 ASSERT(ar != NULL && ar->ar_zsize == AR_SYSTEM_SIZE);
1130
1131 AR_LOCK(ar);
1132 /* retain system-wide sysctls region */
1133 skrsys = skmem_get_sysctls_region();
1134 ASSERT(skrsys != NULL && skrsys->skr_id == SKMEM_REGION_SYSCTLS);
1135 ASSERT((skrsys->skr_mode & (SKR_MODE_MMAPOK | SKR_MODE_NOMAGAZINES |
1136 SKR_MODE_KREADONLY | SKR_MODE_UREADONLY | SKR_MODE_MONOLITHIC |
1137 SKR_MODE_SHAREOK)) ==
1138 (SKR_MODE_MMAPOK | SKR_MODE_NOMAGAZINES | SKR_MODE_UREADONLY |
1139 SKR_MODE_MONOLITHIC));
1140 ar->ar_regions[SKMEM_REGION_SYSCTLS] = skrsys;
1141 skmem_region_retain(skrsys);
1142
1143 /* object is valid as long as the sysctls region is retained */
1144 ars->ars_sysctls_obj = skmem_get_sysctls_obj(&ars->ars_sysctls_objsize);
1145 ASSERT(ars->ars_sysctls_obj != NULL);
1146 ASSERT(ars->ars_sysctls_objsize != 0);
1147
1148 if (skmem_arena_create_finalize(ar) != 0) {
1149 SK_ERR("\"%s\" ar 0x%llx flags %b failed to finalize",
1150 ar->ar_name, SK_KVA(ar), ar->ar_flags, ARF_BITS);
1151 goto failed;
1152 }
1153
1154 /*
1155 * These must never be configured for system arena.
1156 *
1157 * XXX: In theory we can add guard pages to this arena,
1158 * but for now leave that as an exercise for the future.
1159 */
1160 ASSERT(ar->ar_regions[SKMEM_REGION_GUARD_HEAD] == NULL);
1161 ASSERT(ar->ar_regions[SKMEM_REGION_SCHEMA] == NULL);
1162 ASSERT(ar->ar_regions[SKMEM_REGION_RING] == NULL);
1163 ASSERT(ar->ar_regions[SKMEM_REGION_TXAUSD] == NULL);
1164 ASSERT(ar->ar_regions[SKMEM_REGION_RXFUSD] == NULL);
1165 ASSERT(ar->ar_regions[SKMEM_REGION_USTATS] == NULL);
1166 ASSERT(ar->ar_regions[SKMEM_REGION_FLOWADV] == NULL);
1167 ASSERT(ar->ar_regions[SKMEM_REGION_NEXUSADV] == NULL);
1168 ASSERT(ar->ar_regions[SKMEM_REGION_GUARD_TAIL] == NULL);
1169 ASSERT(ar->ar_regions[SKMEM_REGION_TXAKSD] == NULL);
1170 ASSERT(ar->ar_regions[SKMEM_REGION_RXFKSD] == NULL);
1171 ASSERT(ar->ar_regions[SKMEM_REGION_KSTATS] == NULL);
1172 ASSERT(ar->ar_regions[SKMEM_REGION_INTRINSIC] == NULL);
1173 for (int i = 0; i < SKMEM_PP_REGIONS; i++) {
1174 ASSERT(ar->ar_regions[skmem_pp_region_ids[i]] == NULL);
1175 }
1176
1177 /* these must be configured for system arena */
1178 ASSERT(ar->ar_regions[SKMEM_REGION_SYSCTLS] != NULL);
1179
1180 ++ar->ar_refcnt; /* for caller */
1181 AR_UNLOCK(ar);
1182
1183 SKMEM_ARENA_LOCK();
1184 TAILQ_INSERT_TAIL(&skmem_arena_head, ar, ar_link);
1185 SKMEM_ARENA_UNLOCK();
1186
1187 #if SK_LOG
1188 if (__improbable(sk_verbose != 0)) {
1189 skmem_arena_create_region_log(ar);
1190 }
1191 #endif /* SK_LOG */
1192
1193 return ar;
1194
1195 failed:
1196 AR_LOCK_ASSERT_HELD(ar);
1197 skmem_arena_destroy(ar);
1198 *perr = ENOMEM;
1199
1200 return NULL;
1201 }
1202
1203 static void
skmem_arena_system_teardown(struct skmem_arena_system * ars,boolean_t defunct)1204 skmem_arena_system_teardown(struct skmem_arena_system *ars, boolean_t defunct)
1205 {
1206 struct skmem_arena *ar = &ars->ars_cmn;
1207 struct skmem_region *skr;
1208
1209 AR_LOCK_ASSERT_HELD(ar);
1210 ASSERT(ar->ar_type == SKMEM_ARENA_TYPE_SYSTEM);
1211
1212 /* these must never be configured for system arena */
1213 ASSERT(ar->ar_regions[SKMEM_REGION_GUARD_HEAD] == NULL);
1214 ASSERT(ar->ar_regions[SKMEM_REGION_SCHEMA] == NULL);
1215 ASSERT(ar->ar_regions[SKMEM_REGION_RING] == NULL);
1216 ASSERT(ar->ar_regions[SKMEM_REGION_TXAUSD] == NULL);
1217 ASSERT(ar->ar_regions[SKMEM_REGION_RXFUSD] == NULL);
1218 ASSERT(ar->ar_regions[SKMEM_REGION_USTATS] == NULL);
1219 ASSERT(ar->ar_regions[SKMEM_REGION_FLOWADV] == NULL);
1220 ASSERT(ar->ar_regions[SKMEM_REGION_NEXUSADV] == NULL);
1221 ASSERT(ar->ar_regions[SKMEM_REGION_GUARD_TAIL] == NULL);
1222 ASSERT(ar->ar_regions[SKMEM_REGION_TXAKSD] == NULL);
1223 ASSERT(ar->ar_regions[SKMEM_REGION_RXFKSD] == NULL);
1224 ASSERT(ar->ar_regions[SKMEM_REGION_KSTATS] == NULL);
1225 ASSERT(ar->ar_regions[SKMEM_REGION_INTRINSIC] == NULL);
1226 for (int i = 0; i < SKMEM_PP_REGIONS; i++) {
1227 ASSERT(ar->ar_regions[skmem_pp_region_ids[i]] == NULL);
1228 }
1229
1230 /* nothing to do here for now during defunct, just return */
1231 if (defunct) {
1232 return;
1233 }
1234
1235 if (ars->ars_sysctls_obj != NULL) {
1236 skr = ar->ar_regions[SKMEM_REGION_SYSCTLS];
1237 ASSERT(skr != NULL && (skr->skr_mode & SKR_MODE_NOREDIRECT));
1238 /* we didn't allocate this, so don't free it */
1239 ars->ars_sysctls_obj = NULL;
1240 ars->ars_sysctls_objsize = 0;
1241 skmem_region_release(skr);
1242 ar->ar_regions[SKMEM_REGION_SYSCTLS] = NULL;
1243 }
1244 ASSERT(ar->ar_regions[SKMEM_REGION_SYSCTLS] == NULL);
1245 ASSERT(ars->ars_sysctls_obj == NULL);
1246 ASSERT(ars->ars_sysctls_objsize == 0);
1247 }
1248
1249 /*
1250 * Given an arena, return its System variant (if applicable).
1251 */
1252 struct skmem_arena_system *
skmem_arena_system(struct skmem_arena * ar)1253 skmem_arena_system(struct skmem_arena *ar)
1254 {
1255 if (__improbable(ar->ar_type != SKMEM_ARENA_TYPE_SYSTEM)) {
1256 return NULL;
1257 }
1258
1259 return (struct skmem_arena_system *)ar;
1260 }
1261
1262 void *
skmem_arena_system_sysctls_obj_addr(struct skmem_arena * ar)1263 skmem_arena_system_sysctls_obj_addr(struct skmem_arena *ar)
1264 {
1265 ASSERT(ar->ar_type == SKMEM_ARENA_TYPE_SYSTEM);
1266 return skmem_arena_system(ar)->ars_sysctls_obj;
1267 }
1268
1269 size_t
skmem_arena_system_sysctls_obj_size(struct skmem_arena * ar)1270 skmem_arena_system_sysctls_obj_size(struct skmem_arena *ar)
1271 {
1272 ASSERT(ar->ar_type == SKMEM_ARENA_TYPE_SYSTEM);
1273 return skmem_arena_system(ar)->ars_sysctls_objsize;
1274 }
1275
1276 /*
1277 * Destroy a region.
1278 */
1279 static void
skmem_arena_destroy(struct skmem_arena * ar)1280 skmem_arena_destroy(struct skmem_arena *ar)
1281 {
1282 AR_LOCK_ASSERT_HELD(ar);
1283
1284 SK_DF(SK_VERB_MEM_ARENA, "\"%s\" ar 0x%llx flags %b",
1285 ar->ar_name, SK_KVA(ar), ar->ar_flags, ARF_BITS);
1286
1287 ASSERT(ar->ar_refcnt == 0);
1288 if (ar->ar_link.tqe_next != NULL || ar->ar_link.tqe_prev != NULL) {
1289 AR_UNLOCK(ar);
1290 SKMEM_ARENA_LOCK();
1291 TAILQ_REMOVE(&skmem_arena_head, ar, ar_link);
1292 SKMEM_ARENA_UNLOCK();
1293 AR_LOCK(ar);
1294 ASSERT(ar->ar_refcnt == 0);
1295 }
1296
1297 /* teardown all remaining memory regions and associated resources */
1298 skmem_arena_teardown(ar, FALSE);
1299
1300 if (ar->ar_ar != NULL) {
1301 IOSKArenaDestroy(ar->ar_ar);
1302 ar->ar_ar = NULL;
1303 }
1304
1305 if (ar->ar_flags & ARF_ACTIVE) {
1306 ar->ar_flags &= ~ARF_ACTIVE;
1307 }
1308
1309 AR_UNLOCK(ar);
1310
1311 skmem_arena_free(ar);
1312 }
1313
1314 /*
1315 * Teardown (or defunct) a region.
1316 */
1317 static void
skmem_arena_teardown(struct skmem_arena * ar,boolean_t defunct)1318 skmem_arena_teardown(struct skmem_arena *ar, boolean_t defunct)
1319 {
1320 uint32_t i;
1321
1322 switch (ar->ar_type) {
1323 case SKMEM_ARENA_TYPE_NEXUS:
1324 skmem_arena_nexus_teardown((struct skmem_arena_nexus *)ar,
1325 defunct);
1326 break;
1327
1328 case SKMEM_ARENA_TYPE_NECP:
1329 skmem_arena_necp_teardown((struct skmem_arena_necp *)ar,
1330 defunct);
1331 break;
1332
1333 case SKMEM_ARENA_TYPE_SYSTEM:
1334 skmem_arena_system_teardown((struct skmem_arena_system *)ar,
1335 defunct);
1336 break;
1337
1338 default:
1339 VERIFY(0);
1340 /* NOTREACHED */
1341 __builtin_unreachable();
1342 }
1343
1344 /* stop here if we're in the defunct context */
1345 if (defunct) {
1346 return;
1347 }
1348
1349 /* take care of any remaining ones */
1350 for (i = 0; i < SKMEM_REGIONS; i++) {
1351 if (ar->ar_regions[i] == NULL) {
1352 continue;
1353 }
1354
1355 skmem_region_release(ar->ar_regions[i]);
1356 ar->ar_regions[i] = NULL;
1357 }
1358 }
1359
1360 static int
skmem_arena_create_finalize(struct skmem_arena * ar)1361 skmem_arena_create_finalize(struct skmem_arena *ar)
1362 {
1363 IOSKRegionRef reg[SKMEM_REGIONS];
1364 uint32_t i, regcnt = 0;
1365 int err = 0;
1366
1367 AR_LOCK_ASSERT_HELD(ar);
1368
1369 ASSERT(ar->ar_regions[SKMEM_REGION_INTRINSIC] == NULL);
1370
1371 /*
1372 * Prepare an array of regions that can be mapped to user task;
1373 * exclude regions that aren't eligible for user task mapping.
1374 */
1375 bzero(®, sizeof(reg));
1376 for (i = 0; i < SKMEM_REGIONS; i++) {
1377 struct skmem_region *skr = ar->ar_regions[i];
1378 if (skr == NULL || !(skr->skr_mode & SKR_MODE_MMAPOK)) {
1379 continue;
1380 }
1381
1382 ASSERT(skr->skr_reg != NULL);
1383 reg[regcnt++] = skr->skr_reg;
1384 }
1385 ASSERT(regcnt != 0);
1386
1387 /*
1388 * Create backing IOSKArena handle.
1389 */
1390 ar->ar_ar = IOSKArenaCreate(reg, (IOSKCount)regcnt);
1391 if (ar->ar_ar == NULL) {
1392 SK_ERR("\"%s\" ar 0x%llx flags %b failed to create "
1393 "IOSKArena of %u regions", ar->ar_name, SK_KVA(ar),
1394 ar->ar_flags, ARF_BITS, regcnt);
1395 err = ENOMEM;
1396 goto failed;
1397 }
1398
1399 ar->ar_flags |= ARF_ACTIVE;
1400
1401 failed:
1402 return err;
1403 }
1404
1405 static void
skmem_arena_free(struct skmem_arena * ar)1406 skmem_arena_free(struct skmem_arena *ar)
1407 {
1408 #if DEBUG || DEVELOPMENT
1409 ASSERT(ar->ar_refcnt == 0);
1410 ASSERT(!(ar->ar_flags & ARF_ACTIVE));
1411 ASSERT(ar->ar_ar == NULL);
1412 ASSERT(ar->ar_mapcnt == 0);
1413 ASSERT(SLIST_EMPTY(&ar->ar_map_head));
1414 for (uint32_t i = 0; i < SKMEM_REGIONS; i++) {
1415 ASSERT(ar->ar_regions[i] == NULL);
1416 }
1417 #endif /* DEBUG || DEVELOPMENT */
1418
1419 lck_mtx_destroy(&ar->ar_lock, &skmem_arena_lock_grp);
1420 switch (ar->ar_type) {
1421 case SKMEM_ARENA_TYPE_NEXUS:
1422 zfree(ar_nexus_zone, ar);
1423 break;
1424
1425 case SKMEM_ARENA_TYPE_NECP:
1426 zfree(ar_necp_zone, ar);
1427 break;
1428
1429 case SKMEM_ARENA_TYPE_SYSTEM:
1430 zfree(ar_system_zone, ar);
1431 break;
1432
1433 default:
1434 VERIFY(0);
1435 /* NOTREACHED */
1436 __builtin_unreachable();
1437 }
1438 }
1439
1440 /*
1441 * Retain an arena.
1442 */
1443 __attribute__((always_inline))
1444 static inline void
skmem_arena_retain_locked(struct skmem_arena * ar)1445 skmem_arena_retain_locked(struct skmem_arena *ar)
1446 {
1447 AR_LOCK_ASSERT_HELD(ar);
1448 ar->ar_refcnt++;
1449 ASSERT(ar->ar_refcnt != 0);
1450 }
1451
1452 void
skmem_arena_retain(struct skmem_arena * ar)1453 skmem_arena_retain(struct skmem_arena *ar)
1454 {
1455 AR_LOCK(ar);
1456 skmem_arena_retain_locked(ar);
1457 AR_UNLOCK(ar);
1458 }
1459
1460 /*
1461 * Release (and potentially destroy) an arena.
1462 */
1463 __attribute__((always_inline))
1464 static inline boolean_t
skmem_arena_release_locked(struct skmem_arena * ar)1465 skmem_arena_release_locked(struct skmem_arena *ar)
1466 {
1467 boolean_t lastref = FALSE;
1468
1469 AR_LOCK_ASSERT_HELD(ar);
1470 ASSERT(ar->ar_refcnt != 0);
1471 if (--ar->ar_refcnt == 0) {
1472 skmem_arena_destroy(ar);
1473 lastref = TRUE;
1474 } else {
1475 lastref = FALSE;
1476 }
1477
1478 return lastref;
1479 }
1480
1481 boolean_t
skmem_arena_release(struct skmem_arena * ar)1482 skmem_arena_release(struct skmem_arena *ar)
1483 {
1484 boolean_t lastref;
1485
1486 AR_LOCK(ar);
1487 /* unlock only if this isn't the last reference */
1488 if (!(lastref = skmem_arena_release_locked(ar))) {
1489 AR_UNLOCK(ar);
1490 }
1491
1492 return lastref;
1493 }
1494
1495 /*
1496 * Map an arena to the task's address space.
1497 */
1498 int
skmem_arena_mmap(struct skmem_arena * ar,struct proc * p,struct skmem_arena_mmap_info * ami)1499 skmem_arena_mmap(struct skmem_arena *ar, struct proc *p,
1500 struct skmem_arena_mmap_info *ami)
1501 {
1502 struct task *__single task = proc_task(p);
1503 IOReturn ioerr;
1504 int err = 0;
1505
1506 ASSERT(task != kernel_task && task != TASK_NULL);
1507 ASSERT(ami->ami_arena == NULL);
1508 ASSERT(ami->ami_mapref == NULL);
1509 ASSERT(ami->ami_maptask == TASK_NULL);
1510 ASSERT(!ami->ami_redirect);
1511
1512 AR_LOCK(ar);
1513 if ((ar->ar_flags & (ARF_ACTIVE | ARF_DEFUNCT)) != ARF_ACTIVE) {
1514 err = ENODEV;
1515 goto failed;
1516 }
1517
1518 ASSERT(ar->ar_ar != NULL);
1519 if ((ami->ami_mapref = IOSKMapperCreate(ar->ar_ar, task)) == NULL) {
1520 err = ENOMEM;
1521 goto failed;
1522 }
1523
1524 ioerr = IOSKMapperGetAddress(ami->ami_mapref, &ami->ami_mapaddr,
1525 &ami->ami_mapsize);
1526 VERIFY(ioerr == kIOReturnSuccess);
1527
1528 ami->ami_arena = ar;
1529 skmem_arena_retain_locked(ar);
1530 SLIST_INSERT_HEAD(&ar->ar_map_head, ami, ami_link);
1531
1532 ami->ami_maptask = task;
1533 ar->ar_mapcnt++;
1534 if (ar->ar_mapcnt == 1) {
1535 ar->ar_mapsize = ami->ami_mapsize;
1536 }
1537
1538 ASSERT(ami->ami_mapref != NULL);
1539 ASSERT(ami->ami_arena == ar);
1540 AR_UNLOCK(ar);
1541
1542 return 0;
1543
1544 failed:
1545 AR_UNLOCK(ar);
1546 skmem_arena_munmap(ar, ami);
1547 VERIFY(err != 0);
1548
1549 return err;
1550 }
1551
1552 /*
1553 * Remove arena's memory mapping from task's address space (common code).
1554 * Returns true if caller needs to perform a deferred defunct.
1555 */
1556 static boolean_t
skmem_arena_munmap_common(struct skmem_arena * ar,struct skmem_arena_mmap_info * ami)1557 skmem_arena_munmap_common(struct skmem_arena *ar,
1558 struct skmem_arena_mmap_info *ami)
1559 {
1560 boolean_t need_defunct = FALSE;
1561
1562 AR_LOCK(ar);
1563 if (ami->ami_mapref != NULL) {
1564 IOSKMapperDestroy(ami->ami_mapref);
1565 ami->ami_mapref = NULL;
1566
1567 VERIFY(ar->ar_mapcnt != 0);
1568 ar->ar_mapcnt--;
1569 if (ar->ar_mapcnt == 0) {
1570 ar->ar_mapsize = 0;
1571 }
1572
1573 VERIFY(ami->ami_arena == ar);
1574 SLIST_REMOVE(&ar->ar_map_head, ami, skmem_arena_mmap_info,
1575 ami_link);
1576
1577 /*
1578 * We expect that the caller ensures an extra reference
1579 * held on the arena, in addition to the one in mmap_info.
1580 */
1581 VERIFY(ar->ar_refcnt > 1);
1582 (void) skmem_arena_release_locked(ar);
1583 ami->ami_arena = NULL;
1584
1585 if (ami->ami_redirect) {
1586 /*
1587 * This mapper has been redirected; decrement
1588 * the redirect count associated with it.
1589 */
1590 VERIFY(ar->ar_maprdrcnt != 0);
1591 ar->ar_maprdrcnt--;
1592 } else if (ar->ar_maprdrcnt != 0 &&
1593 ar->ar_maprdrcnt == ar->ar_mapcnt) {
1594 /*
1595 * The are other mappers for this arena that have
1596 * all been redirected, but the arena wasn't marked
1597 * inactive by skmem_arena_redirect() last time since
1598 * this particular mapper that we just destroyed
1599 * was using it. Now that it's gone, finish the
1600 * postponed work below once we return to caller.
1601 */
1602 ASSERT(ar->ar_flags & ARF_ACTIVE);
1603 ar->ar_flags &= ~ARF_ACTIVE;
1604 need_defunct = TRUE;
1605 }
1606 }
1607 ASSERT(ami->ami_mapref == NULL);
1608 ASSERT(ami->ami_arena == NULL);
1609
1610 ami->ami_maptask = TASK_NULL;
1611 ami->ami_mapaddr = 0;
1612 ami->ami_mapsize = 0;
1613 ami->ami_redirect = FALSE;
1614
1615 AR_UNLOCK(ar);
1616
1617 return need_defunct;
1618 }
1619
1620 /*
1621 * Remove arena's memory mapping from task's address space (channel version).
1622 * Will perform a deferred defunct if needed.
1623 */
1624 void
skmem_arena_munmap_channel(struct skmem_arena * ar,struct kern_channel * ch)1625 skmem_arena_munmap_channel(struct skmem_arena *ar, struct kern_channel *ch)
1626 {
1627 SK_LOCK_ASSERT_HELD();
1628 LCK_MTX_ASSERT(&ch->ch_lock, LCK_MTX_ASSERT_OWNED);
1629
1630 /*
1631 * If this is this is on a channel that was holding the last
1632 * active reference count on the arena, and that there are
1633 * other defunct channels pointing to that arena, perform the
1634 * actual arena defunct now.
1635 */
1636 if (skmem_arena_munmap_common(ar, &ch->ch_mmap)) {
1637 struct kern_nexus *nx = ch->ch_nexus;
1638 struct kern_nexus_domain_provider *nxdom_prov = NX_DOM_PROV(nx);
1639
1640 /*
1641 * Similar to kern_channel_defunct(), where we let the
1642 * domain provider complete the defunct. At this point
1643 * both sk_lock and the channel locks are held, and so
1644 * we indicate that to the callee.
1645 */
1646 nxdom_prov->nxdom_prov_dom->nxdom_defunct_finalize(nxdom_prov,
1647 nx, ch, TRUE);
1648 }
1649 }
1650
1651 /*
1652 * Remove arena's memory mapping from task's address space (generic).
1653 * This routine should only be called on non-channel related arenas.
1654 */
1655 void
skmem_arena_munmap(struct skmem_arena * ar,struct skmem_arena_mmap_info * ami)1656 skmem_arena_munmap(struct skmem_arena *ar, struct skmem_arena_mmap_info *ami)
1657 {
1658 (void) skmem_arena_munmap_common(ar, ami);
1659 }
1660
1661 /*
1662 * Redirect eligible memory regions in the task's memory map so that
1663 * they get overwritten and backed with anonymous (zero-filled) pages.
1664 */
1665 int
skmem_arena_mredirect(struct skmem_arena * ar,struct skmem_arena_mmap_info * ami,struct proc * p,boolean_t * need_defunct)1666 skmem_arena_mredirect(struct skmem_arena *ar, struct skmem_arena_mmap_info *ami,
1667 struct proc *p, boolean_t *need_defunct)
1668 {
1669 #pragma unused(p)
1670 int err = 0;
1671
1672 *need_defunct = FALSE;
1673
1674 AR_LOCK(ar);
1675 ASSERT(ar->ar_ar != NULL);
1676 if (ami->ami_redirect) {
1677 err = EALREADY;
1678 } else if (ami->ami_mapref == NULL) {
1679 err = ENXIO;
1680 } else {
1681 VERIFY(ar->ar_mapcnt != 0);
1682 ASSERT(ar->ar_flags & ARF_ACTIVE);
1683 VERIFY(ami->ami_arena == ar);
1684 /*
1685 * This effectively overwrites the mappings for all
1686 * redirectable memory regions (i.e. those without the
1687 * SKMEM_REGION_CR_NOREDIRECT flag) while preserving their
1688 * protection flags. Accesses to these regions will be
1689 * redirected to anonymous, zero-filled pages.
1690 */
1691 IOSKMapperRedirect(ami->ami_mapref);
1692 ami->ami_redirect = TRUE;
1693
1694 /*
1695 * Mark the arena as inactive if all mapper instances are
1696 * redirected; otherwise, we do this later during unmap.
1697 * Once inactive, the arena will not allow further mmap,
1698 * and it is ready to be defunct later.
1699 */
1700 if (++ar->ar_maprdrcnt == ar->ar_mapcnt) {
1701 ar->ar_flags &= ~ARF_ACTIVE;
1702 *need_defunct = TRUE;
1703 }
1704 }
1705 AR_UNLOCK(ar);
1706
1707 SK_DF(((err != 0) ? SK_VERB_ERROR : SK_VERB_DEFAULT),
1708 "%s(%d) \"%s\" ar 0x%llx flags %b inactive %u need_defunct %u "
1709 "err %d", sk_proc_name_address(p), sk_proc_pid(p), ar->ar_name,
1710 SK_KVA(ar), ar->ar_flags, ARF_BITS, !(ar->ar_flags & ARF_ACTIVE),
1711 *need_defunct, err);
1712
1713 return err;
1714 }
1715
1716 /*
1717 * Defunct a region.
1718 */
1719 int
skmem_arena_defunct(struct skmem_arena * ar)1720 skmem_arena_defunct(struct skmem_arena *ar)
1721 {
1722 AR_LOCK(ar);
1723
1724 SK_DF(SK_VERB_MEM_ARENA, "\"%s\" ar 0x%llx flags 0x%b", ar->ar_name,
1725 SK_KVA(ar), ar->ar_flags, ARF_BITS);
1726
1727 if (ar->ar_flags & ARF_DEFUNCT) {
1728 AR_UNLOCK(ar);
1729 return EALREADY;
1730 } else if (ar->ar_flags & ARF_ACTIVE) {
1731 AR_UNLOCK(ar);
1732 return EBUSY;
1733 }
1734
1735 /* purge the caches now */
1736 skmem_arena_reap_locked(ar, TRUE);
1737
1738 /* teardown eligible memory regions and associated resources */
1739 skmem_arena_teardown(ar, TRUE);
1740
1741 ar->ar_flags |= ARF_DEFUNCT;
1742
1743 AR_UNLOCK(ar);
1744
1745 return 0;
1746 }
1747
1748 /*
1749 * Retrieve total and in-use memory statistics of regions in the arena.
1750 */
1751 void
skmem_arena_get_stats(struct skmem_arena * ar,uint64_t * mem_total,uint64_t * mem_inuse)1752 skmem_arena_get_stats(struct skmem_arena *ar, uint64_t *mem_total,
1753 uint64_t *mem_inuse)
1754 {
1755 uint32_t i;
1756
1757 if (mem_total != NULL) {
1758 *mem_total = 0;
1759 }
1760 if (mem_inuse != NULL) {
1761 *mem_inuse = 0;
1762 }
1763
1764 AR_LOCK(ar);
1765 for (i = 0; i < SKMEM_REGIONS; i++) {
1766 if (ar->ar_regions[i] == NULL) {
1767 continue;
1768 }
1769
1770 if (mem_total != NULL) {
1771 *mem_total += AR_MEM_TOTAL(ar, i);
1772 }
1773 if (mem_inuse != NULL) {
1774 *mem_inuse += AR_MEM_INUSE(ar, i);
1775 }
1776 }
1777 AR_UNLOCK(ar);
1778 }
1779
1780 /*
1781 * Retrieve the offset of a particular region (identified by its ID)
1782 * from the base of the arena.
1783 */
1784 mach_vm_offset_t
skmem_arena_get_region_offset(struct skmem_arena * ar,skmem_region_id_t id)1785 skmem_arena_get_region_offset(struct skmem_arena *ar, skmem_region_id_t id)
1786 {
1787 mach_vm_offset_t offset = 0;
1788 uint32_t i;
1789
1790 ASSERT(id < SKMEM_REGIONS);
1791
1792 AR_LOCK(ar);
1793 for (i = 0; i < id; i++) {
1794 if (ar->ar_regions[i] == NULL) {
1795 continue;
1796 }
1797
1798 offset += ar->ar_regions[i]->skr_size;
1799 }
1800 AR_UNLOCK(ar);
1801
1802 return offset;
1803 }
1804
1805 static void
skmem_reap_pbufpool_caches(struct kern_pbufpool * pp,boolean_t purge)1806 skmem_reap_pbufpool_caches(struct kern_pbufpool *pp, boolean_t purge)
1807 {
1808 if (pp->pp_kmd_cache != NULL) {
1809 skmem_cache_reap_now(pp->pp_kmd_cache, purge);
1810 }
1811 if (PP_BUF_CACHE_DEF(pp) != NULL) {
1812 skmem_cache_reap_now(PP_BUF_CACHE_DEF(pp), purge);
1813 }
1814 if (PP_BUF_CACHE_LARGE(pp) != NULL) {
1815 skmem_cache_reap_now(PP_BUF_CACHE_LARGE(pp), purge);
1816 }
1817 if (PP_KBFT_CACHE_DEF(pp) != NULL) {
1818 skmem_cache_reap_now(PP_KBFT_CACHE_DEF(pp), purge);
1819 }
1820 if (PP_KBFT_CACHE_LARGE(pp) != NULL) {
1821 skmem_cache_reap_now(PP_KBFT_CACHE_LARGE(pp), purge);
1822 }
1823 }
1824
1825 /*
1826 * Reap all of configured caches in the arena, so that any excess amount
1827 * outside of their working sets gets released to their respective backing
1828 * regions. If purging is specified, we empty the caches' working sets,
1829 * including everything that's cached at the CPU layer.
1830 */
1831 static void
skmem_arena_reap_locked(struct skmem_arena * ar,boolean_t purge)1832 skmem_arena_reap_locked(struct skmem_arena *ar, boolean_t purge)
1833 {
1834 struct skmem_arena_nexus *arn;
1835 struct skmem_arena_necp *arc;
1836 struct kern_pbufpool *pp;
1837
1838 AR_LOCK_ASSERT_HELD(ar);
1839
1840 switch (ar->ar_type) {
1841 case SKMEM_ARENA_TYPE_NEXUS:
1842 arn = (struct skmem_arena_nexus *)ar;
1843 if (arn->arn_schema_cache != NULL) {
1844 skmem_cache_reap_now(arn->arn_schema_cache, purge);
1845 }
1846 if (arn->arn_ring_cache != NULL) {
1847 skmem_cache_reap_now(arn->arn_ring_cache, purge);
1848 }
1849 if ((pp = arn->arn_rx_pp) != NULL) {
1850 skmem_reap_pbufpool_caches(pp, purge);
1851 }
1852 if ((pp = arn->arn_tx_pp) != NULL && pp != arn->arn_rx_pp) {
1853 skmem_reap_pbufpool_caches(pp, purge);
1854 }
1855 break;
1856
1857 case SKMEM_ARENA_TYPE_NECP:
1858 arc = (struct skmem_arena_necp *)ar;
1859 if (arc->arc_kstats_cache != NULL) {
1860 skmem_cache_reap_now(arc->arc_kstats_cache, purge);
1861 }
1862 break;
1863
1864 case SKMEM_ARENA_TYPE_SYSTEM:
1865 break;
1866 }
1867 }
1868
1869 void
skmem_arena_reap(struct skmem_arena * ar,boolean_t purge)1870 skmem_arena_reap(struct skmem_arena *ar, boolean_t purge)
1871 {
1872 AR_LOCK(ar);
1873 skmem_arena_reap_locked(ar, purge);
1874 AR_UNLOCK(ar);
1875 }
1876
1877 #if SK_LOG
1878 SK_LOG_ATTRIBUTE
1879 static void
skmem_arena_create_region_log(struct skmem_arena * ar)1880 skmem_arena_create_region_log(struct skmem_arena *ar)
1881 {
1882 char label[32];
1883 int i;
1884
1885 switch (ar->ar_type) {
1886 case SKMEM_ARENA_TYPE_NEXUS:
1887 SK_D("\"%s\" ar 0x%llx flags %b rx_pp 0x%llx tx_pp 0x%llu",
1888 ar->ar_name, SK_KVA(ar), ar->ar_flags, ARF_BITS,
1889 SK_KVA(skmem_arena_nexus(ar)->arn_rx_pp),
1890 SK_KVA(skmem_arena_nexus(ar)->arn_tx_pp));
1891 break;
1892
1893 case SKMEM_ARENA_TYPE_NECP:
1894 case SKMEM_ARENA_TYPE_SYSTEM:
1895 SK_D("\"%s\" ar 0x%llx flags %b", ar->ar_name,
1896 SK_KVA(ar), ar->ar_flags, ARF_BITS);
1897 break;
1898 }
1899
1900 for (i = 0; i < SKMEM_REGIONS; i++) {
1901 if (ar->ar_regions[i] == NULL) {
1902 continue;
1903 }
1904
1905 (void) snprintf(label, sizeof(label), "REGION_%s:",
1906 skmem_region_id2name(i));
1907 SK_D(" %-16s %6u KB s:[%2u x %6u KB] "
1908 "o:[%4u x %6u -> %4u x %6u]", label,
1909 (uint32_t)AR_MEM_TOTAL(ar, i) >> 10,
1910 (uint32_t)AR_MEM_SEGCNT(ar, i),
1911 (uint32_t)AR_MEM_SEGSIZE(ar, i) >> 10,
1912 (uint32_t)AR_MEM_OBJCNT_R(ar, i),
1913 (uint32_t)AR_MEM_OBJSIZE_R(ar, i),
1914 (uint32_t)AR_MEM_OBJCNT_C(ar, i),
1915 (uint32_t)AR_MEM_OBJSIZE_C(ar, i));
1916 }
1917 }
1918 #endif /* SK_LOG */
1919
1920 static size_t
skmem_arena_mib_get_stats(struct skmem_arena * ar,void * __sized_by (len)out,size_t len)1921 skmem_arena_mib_get_stats(struct skmem_arena *ar, void *__sized_by(len) out,
1922 size_t len)
1923 {
1924 size_t actual_space = sizeof(struct sk_stats_arena);
1925 struct sk_stats_arena *__single sar;
1926 struct skmem_arena_mmap_info *ami = NULL;
1927 pid_t proc_pid;
1928 int i;
1929
1930 if (out == NULL || len < actual_space) {
1931 goto done;
1932 }
1933 sar = out;
1934
1935 AR_LOCK(ar);
1936 (void) snprintf(sar->sar_name, sizeof(sar->sar_name),
1937 "%s", ar->ar_name);
1938 sar->sar_type = (sk_stats_arena_type_t)ar->ar_type;
1939 sar->sar_mapsize = (uint64_t)ar->ar_mapsize;
1940 i = 0;
1941 SLIST_FOREACH(ami, &ar->ar_map_head, ami_link) {
1942 if (ami->ami_arena->ar_type == SKMEM_ARENA_TYPE_NEXUS) {
1943 struct kern_channel *__single ch;
1944 ch = __unsafe_forge_single(struct kern_channel *,
1945 container_of(ami, struct kern_channel, ch_mmap));
1946 proc_pid = ch->ch_pid;
1947 } else {
1948 ASSERT((ami->ami_arena->ar_type ==
1949 SKMEM_ARENA_TYPE_NECP) ||
1950 (ami->ami_arena->ar_type ==
1951 SKMEM_ARENA_TYPE_SYSTEM));
1952 proc_pid =
1953 necp_client_get_proc_pid_from_arena_info(ami);
1954 }
1955 sar->sar_mapped_pids[i++] = proc_pid;
1956 if (i >= SK_STATS_ARENA_MAPPED_PID_MAX) {
1957 break;
1958 }
1959 }
1960
1961 for (i = 0; i < SKMEM_REGIONS; i++) {
1962 struct skmem_region *skr = ar->ar_regions[i];
1963 uuid_t *sreg_uuid = &sar->sar_regions_uuid[i];
1964
1965 if (skr == NULL) {
1966 uuid_clear(*sreg_uuid);
1967 continue;
1968 }
1969
1970 uuid_copy(*sreg_uuid, skr->skr_uuid);
1971 }
1972 AR_UNLOCK(ar);
1973
1974 done:
1975 return actual_space;
1976 }
1977
1978 static int
1979 skmem_arena_mib_get_sysctl SYSCTL_HANDLER_ARGS
1980 {
1981 #pragma unused(arg1, arg2, oidp)
1982 struct skmem_arena *ar;
1983 size_t actual_space;
1984 size_t buffer_space;
1985 size_t allocated_space = 0;
1986 caddr_t __sized_by(allocated_space) buffer = NULL;
1987 caddr_t scan;
1988 int error = 0;
1989
1990 if (!kauth_cred_issuser(kauth_cred_get())) {
1991 return EPERM;
1992 }
1993
1994 net_update_uptime();
1995 buffer_space = req->oldlen;
1996 if (req->oldptr != USER_ADDR_NULL && buffer_space != 0) {
1997 if (buffer_space > SK_SYSCTL_ALLOC_MAX) {
1998 buffer_space = SK_SYSCTL_ALLOC_MAX;
1999 }
2000 caddr_t temp;
2001 temp = sk_alloc_data(buffer_space, Z_WAITOK, skmem_tag_arena_mib);
2002 if (__improbable(temp == NULL)) {
2003 return ENOBUFS;
2004 }
2005 buffer = temp;
2006 allocated_space = buffer_space;
2007 } else if (req->oldptr == USER_ADDR_NULL) {
2008 buffer_space = 0;
2009 }
2010 actual_space = 0;
2011 scan = buffer;
2012
2013 SKMEM_ARENA_LOCK();
2014 TAILQ_FOREACH(ar, &skmem_arena_head, ar_link) {
2015 size_t size = skmem_arena_mib_get_stats(ar, scan, buffer_space);
2016 if (scan != NULL) {
2017 if (buffer_space < size) {
2018 /* supplied buffer too small, stop copying */
2019 error = ENOMEM;
2020 break;
2021 }
2022 scan += size;
2023 buffer_space -= size;
2024 }
2025 actual_space += size;
2026 }
2027 SKMEM_ARENA_UNLOCK();
2028
2029 if (actual_space != 0) {
2030 int out_error = SYSCTL_OUT(req, buffer, actual_space);
2031 if (out_error != 0) {
2032 error = out_error;
2033 }
2034 }
2035 if (buffer != NULL) {
2036 sk_free_data_sized_by(buffer, allocated_space);
2037 }
2038
2039 return error;
2040 }
2041