1*bbb1b6f9SApple OSS Distributions /*
2*bbb1b6f9SApple OSS Distributions * Copyright (c) 2020-2021 Apple Inc. All rights reserved.
3*bbb1b6f9SApple OSS Distributions *
4*bbb1b6f9SApple OSS Distributions * @APPLE_LICENSE_HEADER_START@
5*bbb1b6f9SApple OSS Distributions *
6*bbb1b6f9SApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code
7*bbb1b6f9SApple OSS Distributions * as defined in and that are subject to the Apple Public Source License
8*bbb1b6f9SApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in
9*bbb1b6f9SApple OSS Distributions * compliance with the License. Please obtain a copy of the License at
10*bbb1b6f9SApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this
11*bbb1b6f9SApple OSS Distributions * file.
12*bbb1b6f9SApple OSS Distributions *
13*bbb1b6f9SApple OSS Distributions * The Original Code and all software distributed under the License are
14*bbb1b6f9SApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15*bbb1b6f9SApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16*bbb1b6f9SApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17*bbb1b6f9SApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18*bbb1b6f9SApple OSS Distributions * Please see the License for the specific language governing rights and
19*bbb1b6f9SApple OSS Distributions * limitations under the License.
20*bbb1b6f9SApple OSS Distributions * log_queue_failed_intr);
21*bbb1b6f9SApple OSS Distributions *
22*bbb1b6f9SApple OSS Distributions * @APPLE_LICENSE_HEADER_END@
23*bbb1b6f9SApple OSS Distributions */
24*bbb1b6f9SApple OSS Distributions
25*bbb1b6f9SApple OSS Distributions #include <kern/assert.h>
26*bbb1b6f9SApple OSS Distributions #include <kern/counter.h>
27*bbb1b6f9SApple OSS Distributions #include <kern/cpu_data.h>
28*bbb1b6f9SApple OSS Distributions #include <kern/percpu.h>
29*bbb1b6f9SApple OSS Distributions #include <kern/kalloc.h>
30*bbb1b6f9SApple OSS Distributions #include <kern/thread_call.h>
31*bbb1b6f9SApple OSS Distributions #include <libkern/libkern.h>
32*bbb1b6f9SApple OSS Distributions #include <sys/queue.h>
33*bbb1b6f9SApple OSS Distributions #include <vm/vm_kern.h>
34*bbb1b6f9SApple OSS Distributions #include <sys/sysctl.h>
35*bbb1b6f9SApple OSS Distributions
36*bbb1b6f9SApple OSS Distributions #include "log_queue.h"
37*bbb1b6f9SApple OSS Distributions #include "log_mem.h"
38*bbb1b6f9SApple OSS Distributions
39*bbb1b6f9SApple OSS Distributions #define LQ_DEFAULT_SZ_ORDER 15 // 32K per slot
40*bbb1b6f9SApple OSS Distributions #define LQ_DEFAULT_FREE_AFTER_CNT 15000 // Deallocate log queue after N logs
41*bbb1b6f9SApple OSS Distributions #define LQ_MAX_SZ_ORDER 20 // 1MB per CPU should really be enough and a hard cap
42*bbb1b6f9SApple OSS Distributions #define LQ_MIN_LOG_SZ_ORDER 5
43*bbb1b6f9SApple OSS Distributions #define LQ_MAX_LOG_SZ_ORDER 11
44*bbb1b6f9SApple OSS Distributions #define LQ_BATCH_SIZE 24
45*bbb1b6f9SApple OSS Distributions #define LQ_MAX_LM_SLOTS 9
46*bbb1b6f9SApple OSS Distributions #define LQ_LOW_MEM_SCALE 3
47*bbb1b6f9SApple OSS Distributions #define LQ_MIN_ALLOCATED_LM_SLOTS 2
48*bbb1b6f9SApple OSS Distributions #define LQ_METADATA_START_SLOT 0
49*bbb1b6f9SApple OSS Distributions #define LQ_OTHER_START_SLOT (LQ_MIN_ALLOCATED_LM_SLOTS - 1)
50*bbb1b6f9SApple OSS Distributions
51*bbb1b6f9SApple OSS Distributions #define LQ_MEM_ENABLE(q, i) ((q)->lq_mem_set |= (1 << (i)))
52*bbb1b6f9SApple OSS Distributions #define LQ_MEM_ENABLED(q, i) ((q)->lq_mem_set & (1 << (i)))
53*bbb1b6f9SApple OSS Distributions #define LQ_MEM_DISABLE(q, i) ((q)->lq_mem_set &= ~(1 << (i)))
54*bbb1b6f9SApple OSS Distributions
55*bbb1b6f9SApple OSS Distributions OS_ENUM(log_queue_entry_state, uint8_t,
56*bbb1b6f9SApple OSS Distributions LOG_QUEUE_ENTRY_STATE_INVALID = 0,
57*bbb1b6f9SApple OSS Distributions LOG_QUEUE_ENTRY_STATE_STORED,
58*bbb1b6f9SApple OSS Distributions LOG_QUEUE_ENTRY_STATE_DISPATCHED,
59*bbb1b6f9SApple OSS Distributions LOG_QUEUE_ENTRY_STATE_SENT,
60*bbb1b6f9SApple OSS Distributions LOG_QUEUE_ENTRY_STATE_FAILED
61*bbb1b6f9SApple OSS Distributions );
62*bbb1b6f9SApple OSS Distributions
63*bbb1b6f9SApple OSS Distributions OS_ENUM(lq_mem_state, uint8_t,
64*bbb1b6f9SApple OSS Distributions LQ_MEM_STATE_READY = 0,
65*bbb1b6f9SApple OSS Distributions LQ_MEM_STATE_ALLOCATING,
66*bbb1b6f9SApple OSS Distributions LQ_MEM_STATE_RELEASING
67*bbb1b6f9SApple OSS Distributions );
68*bbb1b6f9SApple OSS Distributions
69*bbb1b6f9SApple OSS Distributions OS_ENUM(lq_req_state, uint8_t,
70*bbb1b6f9SApple OSS Distributions LQ_REQ_STATE_INVALID = 0,
71*bbb1b6f9SApple OSS Distributions LQ_REQ_STATE_ALLOCATING,
72*bbb1b6f9SApple OSS Distributions LQ_REQ_STATE_RELEASING,
73*bbb1b6f9SApple OSS Distributions LQ_REQ_STATE_READY
74*bbb1b6f9SApple OSS Distributions );
75*bbb1b6f9SApple OSS Distributions
76*bbb1b6f9SApple OSS Distributions typedef struct log_queue_entry {
77*bbb1b6f9SApple OSS Distributions STAILQ_ENTRY(log_queue_entry) lqe_link;
78*bbb1b6f9SApple OSS Distributions uint16_t lqe_size;
79*bbb1b6f9SApple OSS Distributions uint16_t lqe_lm_id;
80*bbb1b6f9SApple OSS Distributions _Atomic log_queue_entry_state_t lqe_state;
81*bbb1b6f9SApple OSS Distributions log_payload_s lqe_payload;
82*bbb1b6f9SApple OSS Distributions } log_queue_entry_s, *log_queue_entry_t;
83*bbb1b6f9SApple OSS Distributions
84*bbb1b6f9SApple OSS Distributions typedef STAILQ_HEAD(, log_queue_entry) log_queue_list_s, *log_queue_list_t;
85*bbb1b6f9SApple OSS Distributions
86*bbb1b6f9SApple OSS Distributions typedef struct {
87*bbb1b6f9SApple OSS Distributions log_queue_list_s lq_log_list;
88*bbb1b6f9SApple OSS Distributions log_queue_list_s lq_dispatch_list;
89*bbb1b6f9SApple OSS Distributions logmem_t lq_mem[LQ_MAX_LM_SLOTS];
90*bbb1b6f9SApple OSS Distributions size_t lq_mem_set;
91*bbb1b6f9SApple OSS Distributions size_t lq_mem_size;
92*bbb1b6f9SApple OSS Distributions size_t lq_mem_size_order;
93*bbb1b6f9SApple OSS Distributions lq_mem_state_t lq_mem_state;
94*bbb1b6f9SApple OSS Distributions thread_call_t lq_mem_handler;
95*bbb1b6f9SApple OSS Distributions size_t lq_cnt_mem_active;
96*bbb1b6f9SApple OSS Distributions size_t lq_cnt_mem_avail;
97*bbb1b6f9SApple OSS Distributions size_t lq_cnt_mem_max;
98*bbb1b6f9SApple OSS Distributions size_t lq_cnt_mem_meta_avail;
99*bbb1b6f9SApple OSS Distributions _Atomic lq_req_state_t lq_req_state;
100*bbb1b6f9SApple OSS Distributions void *lq_req_mem;
101*bbb1b6f9SApple OSS Distributions uint32_t lq_ready : 1;
102*bbb1b6f9SApple OSS Distributions uint32_t lq_suspend : 1;
103*bbb1b6f9SApple OSS Distributions } log_queue_s, *log_queue_t;
104*bbb1b6f9SApple OSS Distributions
105*bbb1b6f9SApple OSS Distributions extern bool os_log_disabled(void);
106*bbb1b6f9SApple OSS Distributions
107*bbb1b6f9SApple OSS Distributions /*
108*bbb1b6f9SApple OSS Distributions * Log Queue
109*bbb1b6f9SApple OSS Distributions *
110*bbb1b6f9SApple OSS Distributions * Log queues are allocated and set up per cpu. When a firehose memory is full
111*bbb1b6f9SApple OSS Distributions * logs are stored in a log queue and sent into the firehose once it has a free
112*bbb1b6f9SApple OSS Distributions * space again. Each log queue (memory) can grow and shrink based on demand by
113*bbb1b6f9SApple OSS Distributions * adding/removing additional memory to/from its memory slots. There are
114*bbb1b6f9SApple OSS Distributions * LQ_MAX_LM_SLOTS memory slots available for every log queue to use. Memory
115*bbb1b6f9SApple OSS Distributions * slots are released when not needed, with one slot always allocated per queue
116*bbb1b6f9SApple OSS Distributions * as a minimum.
117*bbb1b6f9SApple OSS Distributions *
118*bbb1b6f9SApple OSS Distributions * Boot args:
119*bbb1b6f9SApple OSS Distributions *
120*bbb1b6f9SApple OSS Distributions * lq_size_order: Per slot memory size defined as a power of 2 exponent
121*bbb1b6f9SApple OSS Distributions * (i.e. 2^lq_bootarg_size_order). Zero disables queues.
122*bbb1b6f9SApple OSS Distributions *
123*bbb1b6f9SApple OSS Distributions * lq_nslots: Number of allocated slots to boot with per each log queue.
124*bbb1b6f9SApple OSS Distributions * Once initial log traffic decreases, log queues release
125*bbb1b6f9SApple OSS Distributions * slots as needed.
126*bbb1b6f9SApple OSS Distributions *
127*bbb1b6f9SApple OSS Distributions * If extensive number of logs is expected, setting aforementioned boot-args as
128*bbb1b6f9SApple OSS Distributions * needed allows to capture the vast majority of logs and avoid drops.
129*bbb1b6f9SApple OSS Distributions */
130*bbb1b6f9SApple OSS Distributions TUNABLE(size_t, lq_bootarg_size_order, "lq_size_order", LQ_DEFAULT_SZ_ORDER);
131*bbb1b6f9SApple OSS Distributions TUNABLE(size_t, lq_bootarg_nslots, "lq_nslots", LQ_MAX_LM_SLOTS);
132*bbb1b6f9SApple OSS Distributions
133*bbb1b6f9SApple OSS Distributions atomic_size_t lq_max_slots = LQ_MAX_LM_SLOTS;
134*bbb1b6f9SApple OSS Distributions #if DEVELOPMENT || DEBUG
135*bbb1b6f9SApple OSS Distributions SYSCTL_UINT(_debug, OID_AUTO, log_queue_max_slots, CTLFLAG_RW, (unsigned int *)&lq_max_slots, 0, "");
136*bbb1b6f9SApple OSS Distributions #endif
137*bbb1b6f9SApple OSS Distributions
138*bbb1b6f9SApple OSS Distributions SCALABLE_COUNTER_DEFINE(log_queue_cnt_received);
139*bbb1b6f9SApple OSS Distributions SCALABLE_COUNTER_DEFINE(log_queue_cnt_rejected_fh);
140*bbb1b6f9SApple OSS Distributions SCALABLE_COUNTER_DEFINE(log_queue_cnt_queued);
141*bbb1b6f9SApple OSS Distributions SCALABLE_COUNTER_DEFINE(log_queue_cnt_sent);
142*bbb1b6f9SApple OSS Distributions SCALABLE_COUNTER_DEFINE(log_queue_cnt_dropped_nomem);
143*bbb1b6f9SApple OSS Distributions SCALABLE_COUNTER_DEFINE(log_queue_cnt_dropped_off);
144*bbb1b6f9SApple OSS Distributions SCALABLE_COUNTER_DEFINE(log_queue_cnt_mem_allocated);
145*bbb1b6f9SApple OSS Distributions SCALABLE_COUNTER_DEFINE(log_queue_cnt_mem_released);
146*bbb1b6f9SApple OSS Distributions SCALABLE_COUNTER_DEFINE(log_queue_cnt_mem_failed);
147*bbb1b6f9SApple OSS Distributions
148*bbb1b6f9SApple OSS Distributions static log_queue_s PERCPU_DATA(oslog_queue);
149*bbb1b6f9SApple OSS Distributions static size_t lq_low_mem_limit;
150*bbb1b6f9SApple OSS Distributions
151*bbb1b6f9SApple OSS Distributions static void *
log_queue_buffer_alloc(size_t amount)152*bbb1b6f9SApple OSS Distributions log_queue_buffer_alloc(size_t amount)
153*bbb1b6f9SApple OSS Distributions {
154*bbb1b6f9SApple OSS Distributions return kalloc_data_tag(amount, Z_WAITOK_ZERO, VM_KERN_MEMORY_LOG);
155*bbb1b6f9SApple OSS Distributions }
156*bbb1b6f9SApple OSS Distributions
157*bbb1b6f9SApple OSS Distributions static void
log_queue_buffer_free(void * addr,size_t amount)158*bbb1b6f9SApple OSS Distributions log_queue_buffer_free(void *addr, size_t amount)
159*bbb1b6f9SApple OSS Distributions {
160*bbb1b6f9SApple OSS Distributions kfree_data(addr, amount);
161*bbb1b6f9SApple OSS Distributions }
162*bbb1b6f9SApple OSS Distributions
163*bbb1b6f9SApple OSS Distributions static void
log_queue_increment_mem_avail(const log_queue_t lq,size_t idx,size_t size)164*bbb1b6f9SApple OSS Distributions log_queue_increment_mem_avail(const log_queue_t lq, size_t idx, size_t size)
165*bbb1b6f9SApple OSS Distributions {
166*bbb1b6f9SApple OSS Distributions lq->lq_cnt_mem_avail += size;
167*bbb1b6f9SApple OSS Distributions if (idx < LQ_OTHER_START_SLOT) {
168*bbb1b6f9SApple OSS Distributions lq->lq_cnt_mem_meta_avail += size;
169*bbb1b6f9SApple OSS Distributions }
170*bbb1b6f9SApple OSS Distributions }
171*bbb1b6f9SApple OSS Distributions
172*bbb1b6f9SApple OSS Distributions static void
log_queue_decrement_mem_avail(const log_queue_t lq,size_t idx,size_t size)173*bbb1b6f9SApple OSS Distributions log_queue_decrement_mem_avail(const log_queue_t lq, size_t idx, size_t size)
174*bbb1b6f9SApple OSS Distributions {
175*bbb1b6f9SApple OSS Distributions lq->lq_cnt_mem_avail -= size;
176*bbb1b6f9SApple OSS Distributions if (idx < LQ_OTHER_START_SLOT) {
177*bbb1b6f9SApple OSS Distributions lq->lq_cnt_mem_meta_avail -= size;
178*bbb1b6f9SApple OSS Distributions }
179*bbb1b6f9SApple OSS Distributions }
180*bbb1b6f9SApple OSS Distributions
181*bbb1b6f9SApple OSS Distributions #define log_queue_entry_size(p) (sizeof(log_queue_entry_s) + (p)->lp_data_size)
182*bbb1b6f9SApple OSS Distributions
183*bbb1b6f9SApple OSS Distributions #define publish(a, v) os_atomic_store((a), (v), release)
184*bbb1b6f9SApple OSS Distributions #define read_dependency(v) os_atomic_load((v), dependency)
185*bbb1b6f9SApple OSS Distributions #define read_dependent(v, t) os_atomic_load_with_dependency_on((v), (uintptr_t)(t))
186*bbb1b6f9SApple OSS Distributions #define read_dependent_w(v, t) ({ \
187*bbb1b6f9SApple OSS Distributions __auto_type _v = os_atomic_inject_dependency((v), (uintptr_t)(t)); \
188*bbb1b6f9SApple OSS Distributions os_atomic_load_wide(_v, dependency); \
189*bbb1b6f9SApple OSS Distributions })
190*bbb1b6f9SApple OSS Distributions
191*bbb1b6f9SApple OSS Distributions static log_queue_entry_state_t
log_queue_entry_state(const log_queue_entry_t lqe)192*bbb1b6f9SApple OSS Distributions log_queue_entry_state(const log_queue_entry_t lqe)
193*bbb1b6f9SApple OSS Distributions {
194*bbb1b6f9SApple OSS Distributions log_queue_entry_state_t state = read_dependency(&lqe->lqe_state);
195*bbb1b6f9SApple OSS Distributions assert(state != LOG_QUEUE_ENTRY_STATE_INVALID);
196*bbb1b6f9SApple OSS Distributions return state;
197*bbb1b6f9SApple OSS Distributions }
198*bbb1b6f9SApple OSS Distributions
199*bbb1b6f9SApple OSS Distributions static log_queue_entry_t
log_queue_entry_alloc(log_queue_t lq,size_t lqe_size,firehose_stream_t stream_type)200*bbb1b6f9SApple OSS Distributions log_queue_entry_alloc(log_queue_t lq, size_t lqe_size, firehose_stream_t stream_type)
201*bbb1b6f9SApple OSS Distributions {
202*bbb1b6f9SApple OSS Distributions // some slots are exclusively reserved for metadata stream
203*bbb1b6f9SApple OSS Distributions short start = LQ_METADATA_START_SLOT;
204*bbb1b6f9SApple OSS Distributions if (stream_type != firehose_stream_metadata) {
205*bbb1b6f9SApple OSS Distributions start = LQ_OTHER_START_SLOT;
206*bbb1b6f9SApple OSS Distributions }
207*bbb1b6f9SApple OSS Distributions
208*bbb1b6f9SApple OSS Distributions for (short i = start; i < LQ_MAX_LM_SLOTS; i++) {
209*bbb1b6f9SApple OSS Distributions if (!LQ_MEM_ENABLED(lq, i)) {
210*bbb1b6f9SApple OSS Distributions continue;
211*bbb1b6f9SApple OSS Distributions }
212*bbb1b6f9SApple OSS Distributions log_queue_entry_t lqe = logmem_alloc(&lq->lq_mem[i], &lqe_size);
213*bbb1b6f9SApple OSS Distributions if (lqe) {
214*bbb1b6f9SApple OSS Distributions assert(lqe_size <= lq->lq_cnt_mem_avail);
215*bbb1b6f9SApple OSS Distributions assert(lqe_size <= UINT16_MAX);
216*bbb1b6f9SApple OSS Distributions log_queue_decrement_mem_avail(lq, i, lqe_size);
217*bbb1b6f9SApple OSS Distributions lqe->lqe_size = (uint16_t)lqe_size;
218*bbb1b6f9SApple OSS Distributions lqe->lqe_lm_id = i;
219*bbb1b6f9SApple OSS Distributions return lqe;
220*bbb1b6f9SApple OSS Distributions }
221*bbb1b6f9SApple OSS Distributions }
222*bbb1b6f9SApple OSS Distributions
223*bbb1b6f9SApple OSS Distributions return NULL;
224*bbb1b6f9SApple OSS Distributions }
225*bbb1b6f9SApple OSS Distributions
226*bbb1b6f9SApple OSS Distributions static void
log_queue_entry_free(log_queue_t lq,log_queue_entry_t lqe)227*bbb1b6f9SApple OSS Distributions log_queue_entry_free(log_queue_t lq, log_queue_entry_t lqe)
228*bbb1b6f9SApple OSS Distributions {
229*bbb1b6f9SApple OSS Distributions const size_t lqe_size = lqe->lqe_size;
230*bbb1b6f9SApple OSS Distributions const uint16_t lqe_lm_id = lqe->lqe_lm_id;
231*bbb1b6f9SApple OSS Distributions
232*bbb1b6f9SApple OSS Distributions bzero(lqe, lqe_size);
233*bbb1b6f9SApple OSS Distributions logmem_free(&lq->lq_mem[lqe_lm_id], lqe, lqe_size);
234*bbb1b6f9SApple OSS Distributions log_queue_increment_mem_avail(lq, lqe_lm_id, lqe_size);
235*bbb1b6f9SApple OSS Distributions }
236*bbb1b6f9SApple OSS Distributions
237*bbb1b6f9SApple OSS Distributions static bool
log_queue_add_entry(log_queue_t lq,log_payload_t lp,const uint8_t * lp_data)238*bbb1b6f9SApple OSS Distributions log_queue_add_entry(log_queue_t lq, log_payload_t lp, const uint8_t *lp_data)
239*bbb1b6f9SApple OSS Distributions {
240*bbb1b6f9SApple OSS Distributions log_queue_entry_t lqe = log_queue_entry_alloc(lq, log_queue_entry_size(lp), lp->lp_stream);
241*bbb1b6f9SApple OSS Distributions if (!lqe) {
242*bbb1b6f9SApple OSS Distributions counter_inc_preemption_disabled(&log_queue_cnt_dropped_nomem);
243*bbb1b6f9SApple OSS Distributions return false;
244*bbb1b6f9SApple OSS Distributions }
245*bbb1b6f9SApple OSS Distributions assert(lqe->lqe_size >= lp->lp_data_size);
246*bbb1b6f9SApple OSS Distributions
247*bbb1b6f9SApple OSS Distributions lqe->lqe_payload = *lp;
248*bbb1b6f9SApple OSS Distributions (void) memcpy((uint8_t *)lqe + sizeof(*lqe), lp_data, lqe->lqe_payload.lp_data_size);
249*bbb1b6f9SApple OSS Distributions STAILQ_INSERT_TAIL(&lq->lq_log_list, lqe, lqe_link);
250*bbb1b6f9SApple OSS Distributions publish(&lqe->lqe_state, LOG_QUEUE_ENTRY_STATE_STORED);
251*bbb1b6f9SApple OSS Distributions
252*bbb1b6f9SApple OSS Distributions counter_inc_preemption_disabled(&log_queue_cnt_queued);
253*bbb1b6f9SApple OSS Distributions
254*bbb1b6f9SApple OSS Distributions return true;
255*bbb1b6f9SApple OSS Distributions }
256*bbb1b6f9SApple OSS Distributions
257*bbb1b6f9SApple OSS Distributions /*
258*bbb1b6f9SApple OSS Distributions * Remove successfully sent logs from a dispatch list and free them.
259*bbb1b6f9SApple OSS Distributions */
260*bbb1b6f9SApple OSS Distributions static size_t
dispatch_list_cleanup(log_queue_t lq)261*bbb1b6f9SApple OSS Distributions dispatch_list_cleanup(log_queue_t lq)
262*bbb1b6f9SApple OSS Distributions {
263*bbb1b6f9SApple OSS Distributions log_queue_entry_t lqe, lqe_tmp;
264*bbb1b6f9SApple OSS Distributions size_t freed = 0;
265*bbb1b6f9SApple OSS Distributions
266*bbb1b6f9SApple OSS Distributions STAILQ_FOREACH_SAFE(lqe, &lq->lq_dispatch_list, lqe_link, lqe_tmp) {
267*bbb1b6f9SApple OSS Distributions log_queue_entry_state_t lqe_state = log_queue_entry_state(lqe);
268*bbb1b6f9SApple OSS Distributions assert(lqe_state != LOG_QUEUE_ENTRY_STATE_STORED);
269*bbb1b6f9SApple OSS Distributions
270*bbb1b6f9SApple OSS Distributions if (lqe_state == LOG_QUEUE_ENTRY_STATE_SENT) {
271*bbb1b6f9SApple OSS Distributions STAILQ_REMOVE(&lq->lq_dispatch_list, lqe, log_queue_entry, lqe_link);
272*bbb1b6f9SApple OSS Distributions publish(&lqe->lqe_state, LOG_QUEUE_ENTRY_STATE_INVALID);
273*bbb1b6f9SApple OSS Distributions log_queue_entry_free(lq, lqe);
274*bbb1b6f9SApple OSS Distributions counter_dec_preemption_disabled(&log_queue_cnt_queued);
275*bbb1b6f9SApple OSS Distributions freed++;
276*bbb1b6f9SApple OSS Distributions }
277*bbb1b6f9SApple OSS Distributions }
278*bbb1b6f9SApple OSS Distributions
279*bbb1b6f9SApple OSS Distributions return freed;
280*bbb1b6f9SApple OSS Distributions }
281*bbb1b6f9SApple OSS Distributions
282*bbb1b6f9SApple OSS Distributions /*
283*bbb1b6f9SApple OSS Distributions * Walk and collect logs stored in the log queue suitable for dispatching.
284*bbb1b6f9SApple OSS Distributions * First, collect previously failed logs, then (if still enough space) grab new
285*bbb1b6f9SApple OSS Distributions * logs.
286*bbb1b6f9SApple OSS Distributions */
287*bbb1b6f9SApple OSS Distributions static size_t
log_dispatch_prepare(log_queue_t lq,size_t requested,log_queue_entry_t * buf)288*bbb1b6f9SApple OSS Distributions log_dispatch_prepare(log_queue_t lq, size_t requested, log_queue_entry_t *buf)
289*bbb1b6f9SApple OSS Distributions {
290*bbb1b6f9SApple OSS Distributions log_queue_entry_t lqe, lqe_tmp;
291*bbb1b6f9SApple OSS Distributions size_t collected = 0;
292*bbb1b6f9SApple OSS Distributions
293*bbb1b6f9SApple OSS Distributions STAILQ_FOREACH(lqe, &lq->lq_dispatch_list, lqe_link) {
294*bbb1b6f9SApple OSS Distributions log_queue_entry_state_t lqe_state = log_queue_entry_state(lqe);
295*bbb1b6f9SApple OSS Distributions assert(lqe_state != LOG_QUEUE_ENTRY_STATE_STORED);
296*bbb1b6f9SApple OSS Distributions
297*bbb1b6f9SApple OSS Distributions if (lqe_state == LOG_QUEUE_ENTRY_STATE_FAILED) {
298*bbb1b6f9SApple OSS Distributions publish(&lqe->lqe_state, LOG_QUEUE_ENTRY_STATE_DISPATCHED);
299*bbb1b6f9SApple OSS Distributions buf[collected++] = lqe;
300*bbb1b6f9SApple OSS Distributions }
301*bbb1b6f9SApple OSS Distributions
302*bbb1b6f9SApple OSS Distributions if (collected == requested) {
303*bbb1b6f9SApple OSS Distributions return collected;
304*bbb1b6f9SApple OSS Distributions }
305*bbb1b6f9SApple OSS Distributions }
306*bbb1b6f9SApple OSS Distributions assert(collected < requested);
307*bbb1b6f9SApple OSS Distributions
308*bbb1b6f9SApple OSS Distributions STAILQ_FOREACH_SAFE(lqe, &lq->lq_log_list, lqe_link, lqe_tmp) {
309*bbb1b6f9SApple OSS Distributions assert(log_queue_entry_state(lqe) == LOG_QUEUE_ENTRY_STATE_STORED);
310*bbb1b6f9SApple OSS Distributions
311*bbb1b6f9SApple OSS Distributions STAILQ_REMOVE(&lq->lq_log_list, lqe, log_queue_entry, lqe_link);
312*bbb1b6f9SApple OSS Distributions STAILQ_INSERT_TAIL(&lq->lq_dispatch_list, lqe, lqe_link);
313*bbb1b6f9SApple OSS Distributions publish(&lqe->lqe_state, LOG_QUEUE_ENTRY_STATE_DISPATCHED);
314*bbb1b6f9SApple OSS Distributions
315*bbb1b6f9SApple OSS Distributions buf[collected++] = lqe;
316*bbb1b6f9SApple OSS Distributions if (collected == requested) {
317*bbb1b6f9SApple OSS Distributions break;
318*bbb1b6f9SApple OSS Distributions }
319*bbb1b6f9SApple OSS Distributions }
320*bbb1b6f9SApple OSS Distributions
321*bbb1b6f9SApple OSS Distributions return collected;
322*bbb1b6f9SApple OSS Distributions }
323*bbb1b6f9SApple OSS Distributions
324*bbb1b6f9SApple OSS Distributions /*
325*bbb1b6f9SApple OSS Distributions * Send dispatched logs to the firehose. Skip streaming when replaying.
326*bbb1b6f9SApple OSS Distributions * Streaming does not process timestamps and would therefore show logs out of
327*bbb1b6f9SApple OSS Distributions * order.
328*bbb1b6f9SApple OSS Distributions */
329*bbb1b6f9SApple OSS Distributions static void
log_queue_dispatch_logs(size_t logs_count,log_queue_entry_t * logs)330*bbb1b6f9SApple OSS Distributions log_queue_dispatch_logs(size_t logs_count, log_queue_entry_t *logs)
331*bbb1b6f9SApple OSS Distributions {
332*bbb1b6f9SApple OSS Distributions for (size_t i = 0; i < logs_count; i++) {
333*bbb1b6f9SApple OSS Distributions const log_queue_entry_t lqe = logs[i];
334*bbb1b6f9SApple OSS Distributions log_queue_entry_state_t lqe_state = log_queue_entry_state(lqe);
335*bbb1b6f9SApple OSS Distributions
336*bbb1b6f9SApple OSS Distributions if (lqe_state == LOG_QUEUE_ENTRY_STATE_DISPATCHED) {
337*bbb1b6f9SApple OSS Distributions const log_payload_t lqe_lp = &lqe->lqe_payload;
338*bbb1b6f9SApple OSS Distributions
339*bbb1b6f9SApple OSS Distributions log_payload_s lp = {
340*bbb1b6f9SApple OSS Distributions .lp_ftid = read_dependent_w(&lqe_lp->lp_ftid, lqe_state),
341*bbb1b6f9SApple OSS Distributions .lp_timestamp = read_dependent_w(&lqe_lp->lp_timestamp, lqe_state),
342*bbb1b6f9SApple OSS Distributions .lp_stream = read_dependent(&lqe_lp->lp_stream, lqe_state),
343*bbb1b6f9SApple OSS Distributions .lp_pub_data_size = read_dependent(&lqe_lp->lp_pub_data_size, lqe_state),
344*bbb1b6f9SApple OSS Distributions .lp_data_size = read_dependent(&lqe_lp->lp_data_size, lqe_state)
345*bbb1b6f9SApple OSS Distributions };
346*bbb1b6f9SApple OSS Distributions const void *lp_data = (uint8_t *)lqe + sizeof(*lqe);
347*bbb1b6f9SApple OSS Distributions
348*bbb1b6f9SApple OSS Distributions /*
349*bbb1b6f9SApple OSS Distributions * The log queue mechanism expects only the state to be
350*bbb1b6f9SApple OSS Distributions * modified here since we are likely running on a
351*bbb1b6f9SApple OSS Distributions * different cpu. Queue cleanup will be done safely
352*bbb1b6f9SApple OSS Distributions * later in dispatch_list_cleanup().
353*bbb1b6f9SApple OSS Distributions */
354*bbb1b6f9SApple OSS Distributions if (log_payload_send(&lp, lp_data, false)) {
355*bbb1b6f9SApple OSS Distributions publish(&lqe->lqe_state, LOG_QUEUE_ENTRY_STATE_SENT);
356*bbb1b6f9SApple OSS Distributions counter_inc(&log_queue_cnt_sent);
357*bbb1b6f9SApple OSS Distributions } else {
358*bbb1b6f9SApple OSS Distributions publish(&lqe->lqe_state, LOG_QUEUE_ENTRY_STATE_FAILED);
359*bbb1b6f9SApple OSS Distributions }
360*bbb1b6f9SApple OSS Distributions }
361*bbb1b6f9SApple OSS Distributions }
362*bbb1b6f9SApple OSS Distributions }
363*bbb1b6f9SApple OSS Distributions
364*bbb1b6f9SApple OSS Distributions static bool
log_queue_empty(const log_queue_t lq)365*bbb1b6f9SApple OSS Distributions log_queue_empty(const log_queue_t lq)
366*bbb1b6f9SApple OSS Distributions {
367*bbb1b6f9SApple OSS Distributions return STAILQ_EMPTY(&lq->lq_log_list) && STAILQ_EMPTY(&lq->lq_dispatch_list);
368*bbb1b6f9SApple OSS Distributions }
369*bbb1b6f9SApple OSS Distributions
370*bbb1b6f9SApple OSS Distributions static boolean_t
log_queue_low_mem(const log_queue_t lq)371*bbb1b6f9SApple OSS Distributions log_queue_low_mem(const log_queue_t lq)
372*bbb1b6f9SApple OSS Distributions {
373*bbb1b6f9SApple OSS Distributions size_t mem_avail = lq->lq_cnt_mem_avail - lq->lq_cnt_mem_meta_avail;
374*bbb1b6f9SApple OSS Distributions size_t low_mem_threshold = (lq->lq_cnt_mem_active - LQ_OTHER_START_SLOT) * lq_low_mem_limit;
375*bbb1b6f9SApple OSS Distributions return mem_avail < low_mem_threshold;
376*bbb1b6f9SApple OSS Distributions }
377*bbb1b6f9SApple OSS Distributions
378*bbb1b6f9SApple OSS Distributions static lq_req_state_t
log_queue_request_state(log_queue_t lq)379*bbb1b6f9SApple OSS Distributions log_queue_request_state(log_queue_t lq)
380*bbb1b6f9SApple OSS Distributions {
381*bbb1b6f9SApple OSS Distributions lq_req_state_t req_state = read_dependency(&lq->lq_req_state);
382*bbb1b6f9SApple OSS Distributions return req_state;
383*bbb1b6f9SApple OSS Distributions }
384*bbb1b6f9SApple OSS Distributions
385*bbb1b6f9SApple OSS Distributions static void
log_queue_mem_init(log_queue_t lq,size_t idx,void * buf,size_t buflen)386*bbb1b6f9SApple OSS Distributions log_queue_mem_init(log_queue_t lq, size_t idx, void *buf, size_t buflen)
387*bbb1b6f9SApple OSS Distributions {
388*bbb1b6f9SApple OSS Distributions assert(buf);
389*bbb1b6f9SApple OSS Distributions assert(buflen > 0);
390*bbb1b6f9SApple OSS Distributions assert(idx < LQ_MAX_LM_SLOTS);
391*bbb1b6f9SApple OSS Distributions assert(!LQ_MEM_ENABLED(lq, idx));
392*bbb1b6f9SApple OSS Distributions
393*bbb1b6f9SApple OSS Distributions logmem_init(&lq->lq_mem[idx], buf, buflen, lq->lq_mem_size_order,
394*bbb1b6f9SApple OSS Distributions LQ_MIN_LOG_SZ_ORDER, LQ_MAX_LOG_SZ_ORDER);
395*bbb1b6f9SApple OSS Distributions }
396*bbb1b6f9SApple OSS Distributions
397*bbb1b6f9SApple OSS Distributions void
log_queue_set_max_slots(size_t max_slots)398*bbb1b6f9SApple OSS Distributions log_queue_set_max_slots(size_t max_slots)
399*bbb1b6f9SApple OSS Distributions {
400*bbb1b6f9SApple OSS Distributions max_slots = MAX(max_slots, LQ_MIN_ALLOCATED_LM_SLOTS);
401*bbb1b6f9SApple OSS Distributions assert(max_slots <= LQ_MAX_LM_SLOTS);
402*bbb1b6f9SApple OSS Distributions assert(max_slots >= LQ_MIN_ALLOCATED_LM_SLOTS);
403*bbb1b6f9SApple OSS Distributions atomic_store_explicit((atomic_size_t *)&lq_max_slots, max_slots, memory_order_relaxed);
404*bbb1b6f9SApple OSS Distributions }
405*bbb1b6f9SApple OSS Distributions
406*bbb1b6f9SApple OSS Distributions static size_t
log_queue_mem_max_slots(void)407*bbb1b6f9SApple OSS Distributions log_queue_mem_max_slots(void)
408*bbb1b6f9SApple OSS Distributions {
409*bbb1b6f9SApple OSS Distributions size_t max_slots = atomic_load_explicit((atomic_size_t *)&lq_max_slots, memory_order_relaxed);
410*bbb1b6f9SApple OSS Distributions max_slots = MAX(max_slots, LQ_MIN_ALLOCATED_LM_SLOTS);
411*bbb1b6f9SApple OSS Distributions assert(max_slots <= LQ_MAX_LM_SLOTS);
412*bbb1b6f9SApple OSS Distributions assert(max_slots >= LQ_MIN_ALLOCATED_LM_SLOTS);
413*bbb1b6f9SApple OSS Distributions return max_slots;
414*bbb1b6f9SApple OSS Distributions }
415*bbb1b6f9SApple OSS Distributions
416*bbb1b6f9SApple OSS Distributions static int
log_queue_mem_free_slot(log_queue_t lq)417*bbb1b6f9SApple OSS Distributions log_queue_mem_free_slot(log_queue_t lq)
418*bbb1b6f9SApple OSS Distributions {
419*bbb1b6f9SApple OSS Distributions assert(LQ_MEM_ENABLED(lq, 0));
420*bbb1b6f9SApple OSS Distributions assert(lq->lq_cnt_mem_max <= LQ_MAX_LM_SLOTS);
421*bbb1b6f9SApple OSS Distributions
422*bbb1b6f9SApple OSS Distributions for (int i = LQ_MIN_ALLOCATED_LM_SLOTS; i < lq->lq_cnt_mem_max; i++) {
423*bbb1b6f9SApple OSS Distributions if (!LQ_MEM_ENABLED(lq, i)) {
424*bbb1b6f9SApple OSS Distributions return i;
425*bbb1b6f9SApple OSS Distributions }
426*bbb1b6f9SApple OSS Distributions }
427*bbb1b6f9SApple OSS Distributions return -1;
428*bbb1b6f9SApple OSS Distributions }
429*bbb1b6f9SApple OSS Distributions
430*bbb1b6f9SApple OSS Distributions static void
log_queue_memory_handler(thread_call_param_t a0,__unused thread_call_param_t a1)431*bbb1b6f9SApple OSS Distributions log_queue_memory_handler(thread_call_param_t a0, __unused thread_call_param_t a1)
432*bbb1b6f9SApple OSS Distributions {
433*bbb1b6f9SApple OSS Distributions log_queue_t lq = (log_queue_t)a0;
434*bbb1b6f9SApple OSS Distributions lq_req_state_t req_state = log_queue_request_state(lq);
435*bbb1b6f9SApple OSS Distributions
436*bbb1b6f9SApple OSS Distributions assert(req_state != LQ_REQ_STATE_INVALID);
437*bbb1b6f9SApple OSS Distributions
438*bbb1b6f9SApple OSS Distributions if (req_state == LQ_REQ_STATE_ALLOCATING) {
439*bbb1b6f9SApple OSS Distributions lq->lq_req_mem = log_queue_buffer_alloc(lq->lq_mem_size);
440*bbb1b6f9SApple OSS Distributions publish(&lq->lq_req_state, LQ_REQ_STATE_READY);
441*bbb1b6f9SApple OSS Distributions
442*bbb1b6f9SApple OSS Distributions if (lq->lq_req_mem) {
443*bbb1b6f9SApple OSS Distributions counter_inc(&log_queue_cnt_mem_allocated);
444*bbb1b6f9SApple OSS Distributions } else {
445*bbb1b6f9SApple OSS Distributions counter_inc(&log_queue_cnt_mem_failed);
446*bbb1b6f9SApple OSS Distributions }
447*bbb1b6f9SApple OSS Distributions } else if (req_state == LQ_REQ_STATE_RELEASING) {
448*bbb1b6f9SApple OSS Distributions void *buf = read_dependent(&lq->lq_req_mem, req_state);
449*bbb1b6f9SApple OSS Distributions
450*bbb1b6f9SApple OSS Distributions log_queue_buffer_free(buf, lq->lq_mem_size);
451*bbb1b6f9SApple OSS Distributions lq->lq_req_mem = NULL;
452*bbb1b6f9SApple OSS Distributions publish(&lq->lq_req_state, LQ_REQ_STATE_READY);
453*bbb1b6f9SApple OSS Distributions
454*bbb1b6f9SApple OSS Distributions counter_inc(&log_queue_cnt_mem_released);
455*bbb1b6f9SApple OSS Distributions }
456*bbb1b6f9SApple OSS Distributions }
457*bbb1b6f9SApple OSS Distributions
458*bbb1b6f9SApple OSS Distributions static void
log_queue_order_memory(log_queue_t lq)459*bbb1b6f9SApple OSS Distributions log_queue_order_memory(log_queue_t lq)
460*bbb1b6f9SApple OSS Distributions {
461*bbb1b6f9SApple OSS Distributions boolean_t __assert_only running;
462*bbb1b6f9SApple OSS Distributions
463*bbb1b6f9SApple OSS Distributions lq->lq_req_mem = NULL;
464*bbb1b6f9SApple OSS Distributions publish(&lq->lq_req_state, LQ_REQ_STATE_ALLOCATING);
465*bbb1b6f9SApple OSS Distributions
466*bbb1b6f9SApple OSS Distributions running = thread_call_enter(lq->lq_mem_handler);
467*bbb1b6f9SApple OSS Distributions assert(!running);
468*bbb1b6f9SApple OSS Distributions }
469*bbb1b6f9SApple OSS Distributions
470*bbb1b6f9SApple OSS Distributions static void
log_queue_release_memory(log_queue_t lq,void * buf)471*bbb1b6f9SApple OSS Distributions log_queue_release_memory(log_queue_t lq, void *buf)
472*bbb1b6f9SApple OSS Distributions {
473*bbb1b6f9SApple OSS Distributions boolean_t __assert_only running;
474*bbb1b6f9SApple OSS Distributions
475*bbb1b6f9SApple OSS Distributions assert(buf);
476*bbb1b6f9SApple OSS Distributions lq->lq_req_mem = buf;
477*bbb1b6f9SApple OSS Distributions publish(&lq->lq_req_state, LQ_REQ_STATE_RELEASING);
478*bbb1b6f9SApple OSS Distributions
479*bbb1b6f9SApple OSS Distributions running = thread_call_enter(lq->lq_mem_handler);
480*bbb1b6f9SApple OSS Distributions assert(!running);
481*bbb1b6f9SApple OSS Distributions }
482*bbb1b6f9SApple OSS Distributions
483*bbb1b6f9SApple OSS Distributions static void
log_queue_mem_enable(log_queue_t lq,size_t i)484*bbb1b6f9SApple OSS Distributions log_queue_mem_enable(log_queue_t lq, size_t i)
485*bbb1b6f9SApple OSS Distributions {
486*bbb1b6f9SApple OSS Distributions logmem_t *lm = &lq->lq_mem[i];
487*bbb1b6f9SApple OSS Distributions assert(!LQ_MEM_ENABLED(lq, i));
488*bbb1b6f9SApple OSS Distributions
489*bbb1b6f9SApple OSS Distributions LQ_MEM_ENABLE(lq, i);
490*bbb1b6f9SApple OSS Distributions lq->lq_cnt_mem_active++;
491*bbb1b6f9SApple OSS Distributions log_queue_increment_mem_avail(lq, i, lm->lm_cnt_free);
492*bbb1b6f9SApple OSS Distributions }
493*bbb1b6f9SApple OSS Distributions
494*bbb1b6f9SApple OSS Distributions static void
log_queue_mem_disable(log_queue_t lq,size_t i)495*bbb1b6f9SApple OSS Distributions log_queue_mem_disable(log_queue_t lq, size_t i)
496*bbb1b6f9SApple OSS Distributions {
497*bbb1b6f9SApple OSS Distributions logmem_t *lm = &lq->lq_mem[i];
498*bbb1b6f9SApple OSS Distributions assert(LQ_MEM_ENABLED(lq, i));
499*bbb1b6f9SApple OSS Distributions
500*bbb1b6f9SApple OSS Distributions LQ_MEM_DISABLE(lq, i);
501*bbb1b6f9SApple OSS Distributions lq->lq_cnt_mem_active--;
502*bbb1b6f9SApple OSS Distributions log_queue_decrement_mem_avail(lq, i, lm->lm_cnt_free);
503*bbb1b6f9SApple OSS Distributions }
504*bbb1b6f9SApple OSS Distributions
505*bbb1b6f9SApple OSS Distributions static void *
log_queue_mem_reclaim(log_queue_t lq)506*bbb1b6f9SApple OSS Distributions log_queue_mem_reclaim(log_queue_t lq)
507*bbb1b6f9SApple OSS Distributions {
508*bbb1b6f9SApple OSS Distributions for (int i = LQ_MIN_ALLOCATED_LM_SLOTS; i < LQ_MAX_LM_SLOTS; i++) {
509*bbb1b6f9SApple OSS Distributions logmem_t *lm = &lq->lq_mem[i];
510*bbb1b6f9SApple OSS Distributions if (LQ_MEM_ENABLED(lq, i) && logmem_empty(lm)) {
511*bbb1b6f9SApple OSS Distributions assert(lm->lm_mem_size == lq->lq_mem_size);
512*bbb1b6f9SApple OSS Distributions void *reclaimed = lm->lm_mem;
513*bbb1b6f9SApple OSS Distributions log_queue_mem_disable(lq, i);
514*bbb1b6f9SApple OSS Distributions /* Do not use bzero here, see rdar://116922009 */
515*bbb1b6f9SApple OSS Distributions *lm = (logmem_t){ };
516*bbb1b6f9SApple OSS Distributions return reclaimed;
517*bbb1b6f9SApple OSS Distributions }
518*bbb1b6f9SApple OSS Distributions }
519*bbb1b6f9SApple OSS Distributions return NULL;
520*bbb1b6f9SApple OSS Distributions }
521*bbb1b6f9SApple OSS Distributions
522*bbb1b6f9SApple OSS Distributions static void
log_queue_mem_reconfigure(log_queue_t lq)523*bbb1b6f9SApple OSS Distributions log_queue_mem_reconfigure(log_queue_t lq)
524*bbb1b6f9SApple OSS Distributions {
525*bbb1b6f9SApple OSS Distributions assert(lq->lq_mem_state == LQ_MEM_STATE_ALLOCATING ||
526*bbb1b6f9SApple OSS Distributions lq->lq_mem_state == LQ_MEM_STATE_RELEASING);
527*bbb1b6f9SApple OSS Distributions
528*bbb1b6f9SApple OSS Distributions lq_req_state_t req_state = log_queue_request_state(lq);
529*bbb1b6f9SApple OSS Distributions
530*bbb1b6f9SApple OSS Distributions if (req_state == LQ_REQ_STATE_READY) {
531*bbb1b6f9SApple OSS Distributions if (lq->lq_mem_state == LQ_MEM_STATE_ALLOCATING) {
532*bbb1b6f9SApple OSS Distributions void *buf = read_dependent(&lq->lq_req_mem, req_state);
533*bbb1b6f9SApple OSS Distributions if (buf) {
534*bbb1b6f9SApple OSS Distributions const int i = log_queue_mem_free_slot(lq);
535*bbb1b6f9SApple OSS Distributions assert(i > 0);
536*bbb1b6f9SApple OSS Distributions log_queue_mem_init(lq, i, buf, lq->lq_mem_size);
537*bbb1b6f9SApple OSS Distributions log_queue_mem_enable(lq, i);
538*bbb1b6f9SApple OSS Distributions }
539*bbb1b6f9SApple OSS Distributions }
540*bbb1b6f9SApple OSS Distributions lq->lq_mem_state = LQ_MEM_STATE_READY;
541*bbb1b6f9SApple OSS Distributions publish(&lq->lq_req_state, LQ_REQ_STATE_INVALID);
542*bbb1b6f9SApple OSS Distributions }
543*bbb1b6f9SApple OSS Distributions }
544*bbb1b6f9SApple OSS Distributions
545*bbb1b6f9SApple OSS Distributions static boolean_t
log_queue_needs_memory(log_queue_t lq,boolean_t new_suspend)546*bbb1b6f9SApple OSS Distributions log_queue_needs_memory(log_queue_t lq, boolean_t new_suspend)
547*bbb1b6f9SApple OSS Distributions {
548*bbb1b6f9SApple OSS Distributions // Store the current upper bound before potentially growing the queue.
549*bbb1b6f9SApple OSS Distributions lq->lq_cnt_mem_max = log_queue_mem_max_slots();
550*bbb1b6f9SApple OSS Distributions
551*bbb1b6f9SApple OSS Distributions if (new_suspend || log_queue_low_mem(lq)) {
552*bbb1b6f9SApple OSS Distributions return lq->lq_cnt_mem_active < lq->lq_cnt_mem_max;
553*bbb1b6f9SApple OSS Distributions }
554*bbb1b6f9SApple OSS Distributions return false;
555*bbb1b6f9SApple OSS Distributions }
556*bbb1b6f9SApple OSS Distributions
557*bbb1b6f9SApple OSS Distributions static boolean_t
log_queue_can_release_memory(log_queue_t lq)558*bbb1b6f9SApple OSS Distributions log_queue_can_release_memory(log_queue_t lq)
559*bbb1b6f9SApple OSS Distributions {
560*bbb1b6f9SApple OSS Distributions assert(lq->lq_mem_state == LQ_MEM_STATE_READY);
561*bbb1b6f9SApple OSS Distributions
562*bbb1b6f9SApple OSS Distributions if (lq->lq_cnt_mem_active > LQ_MIN_ALLOCATED_LM_SLOTS
563*bbb1b6f9SApple OSS Distributions && log_queue_empty(lq) && !lq->lq_suspend) {
564*bbb1b6f9SApple OSS Distributions const uint64_t total_log_cnt = counter_load(&log_queue_cnt_received);
565*bbb1b6f9SApple OSS Distributions return total_log_cnt > LQ_DEFAULT_FREE_AFTER_CNT;
566*bbb1b6f9SApple OSS Distributions }
567*bbb1b6f9SApple OSS Distributions return false;
568*bbb1b6f9SApple OSS Distributions }
569*bbb1b6f9SApple OSS Distributions
570*bbb1b6f9SApple OSS Distributions extern boolean_t tasks_suspend_state;
571*bbb1b6f9SApple OSS Distributions
572*bbb1b6f9SApple OSS Distributions static boolean_t
detect_new_suspend(log_queue_t lq)573*bbb1b6f9SApple OSS Distributions detect_new_suspend(log_queue_t lq)
574*bbb1b6f9SApple OSS Distributions {
575*bbb1b6f9SApple OSS Distributions if (!tasks_suspend_state) {
576*bbb1b6f9SApple OSS Distributions lq->lq_suspend = false;
577*bbb1b6f9SApple OSS Distributions return false;
578*bbb1b6f9SApple OSS Distributions }
579*bbb1b6f9SApple OSS Distributions
580*bbb1b6f9SApple OSS Distributions if (!lq->lq_suspend) {
581*bbb1b6f9SApple OSS Distributions lq->lq_suspend = true;
582*bbb1b6f9SApple OSS Distributions return true;
583*bbb1b6f9SApple OSS Distributions }
584*bbb1b6f9SApple OSS Distributions
585*bbb1b6f9SApple OSS Distributions return false;
586*bbb1b6f9SApple OSS Distributions }
587*bbb1b6f9SApple OSS Distributions
588*bbb1b6f9SApple OSS Distributions static void
log_queue_dispatch(void)589*bbb1b6f9SApple OSS Distributions log_queue_dispatch(void)
590*bbb1b6f9SApple OSS Distributions {
591*bbb1b6f9SApple OSS Distributions lq_mem_state_t new_mem_state = LQ_MEM_STATE_READY;
592*bbb1b6f9SApple OSS Distributions void *reclaimed_memory = NULL;
593*bbb1b6f9SApple OSS Distributions
594*bbb1b6f9SApple OSS Distributions disable_preemption();
595*bbb1b6f9SApple OSS Distributions
596*bbb1b6f9SApple OSS Distributions log_queue_t lq = PERCPU_GET(oslog_queue);
597*bbb1b6f9SApple OSS Distributions if (__improbable(!lq->lq_ready)) {
598*bbb1b6f9SApple OSS Distributions enable_preemption();
599*bbb1b6f9SApple OSS Distributions return;
600*bbb1b6f9SApple OSS Distributions }
601*bbb1b6f9SApple OSS Distributions
602*bbb1b6f9SApple OSS Distributions dispatch_list_cleanup(lq);
603*bbb1b6f9SApple OSS Distributions
604*bbb1b6f9SApple OSS Distributions log_queue_entry_t logs[LQ_BATCH_SIZE];
605*bbb1b6f9SApple OSS Distributions size_t logs_count = log_dispatch_prepare(lq, LQ_BATCH_SIZE, (log_queue_entry_t *)&logs);
606*bbb1b6f9SApple OSS Distributions
607*bbb1b6f9SApple OSS Distributions boolean_t new_suspend = detect_new_suspend(lq);
608*bbb1b6f9SApple OSS Distributions
609*bbb1b6f9SApple OSS Distributions if (__improbable(lq->lq_mem_state != LQ_MEM_STATE_READY)) {
610*bbb1b6f9SApple OSS Distributions log_queue_mem_reconfigure(lq);
611*bbb1b6f9SApple OSS Distributions } else if (logs_count == 0 && log_queue_can_release_memory(lq)) {
612*bbb1b6f9SApple OSS Distributions reclaimed_memory = log_queue_mem_reclaim(lq);
613*bbb1b6f9SApple OSS Distributions if (reclaimed_memory) {
614*bbb1b6f9SApple OSS Distributions lq->lq_mem_state = LQ_MEM_STATE_RELEASING;
615*bbb1b6f9SApple OSS Distributions new_mem_state = lq->lq_mem_state;
616*bbb1b6f9SApple OSS Distributions }
617*bbb1b6f9SApple OSS Distributions } else if (log_queue_needs_memory(lq, new_suspend)) {
618*bbb1b6f9SApple OSS Distributions lq->lq_mem_state = LQ_MEM_STATE_ALLOCATING;
619*bbb1b6f9SApple OSS Distributions new_mem_state = lq->lq_mem_state;
620*bbb1b6f9SApple OSS Distributions }
621*bbb1b6f9SApple OSS Distributions
622*bbb1b6f9SApple OSS Distributions enable_preemption();
623*bbb1b6f9SApple OSS Distributions
624*bbb1b6f9SApple OSS Distributions switch (new_mem_state) {
625*bbb1b6f9SApple OSS Distributions case LQ_MEM_STATE_RELEASING:
626*bbb1b6f9SApple OSS Distributions assert(logs_count == 0);
627*bbb1b6f9SApple OSS Distributions log_queue_release_memory(lq, reclaimed_memory);
628*bbb1b6f9SApple OSS Distributions break;
629*bbb1b6f9SApple OSS Distributions case LQ_MEM_STATE_ALLOCATING:
630*bbb1b6f9SApple OSS Distributions log_queue_order_memory(lq);
631*bbb1b6f9SApple OSS Distributions /* FALLTHROUGH */
632*bbb1b6f9SApple OSS Distributions case LQ_MEM_STATE_READY:
633*bbb1b6f9SApple OSS Distributions log_queue_dispatch_logs(logs_count, logs);
634*bbb1b6f9SApple OSS Distributions break;
635*bbb1b6f9SApple OSS Distributions default:
636*bbb1b6f9SApple OSS Distributions panic("Invalid log memory state %u", new_mem_state);
637*bbb1b6f9SApple OSS Distributions break;
638*bbb1b6f9SApple OSS Distributions }
639*bbb1b6f9SApple OSS Distributions }
640*bbb1b6f9SApple OSS Distributions
641*bbb1b6f9SApple OSS Distributions static bool
log_queue_add(log_payload_t lp,const uint8_t * lp_data)642*bbb1b6f9SApple OSS Distributions log_queue_add(log_payload_t lp, const uint8_t *lp_data)
643*bbb1b6f9SApple OSS Distributions {
644*bbb1b6f9SApple OSS Distributions boolean_t order_memory = false;
645*bbb1b6f9SApple OSS Distributions
646*bbb1b6f9SApple OSS Distributions disable_preemption();
647*bbb1b6f9SApple OSS Distributions
648*bbb1b6f9SApple OSS Distributions log_queue_t lq = PERCPU_GET(oslog_queue);
649*bbb1b6f9SApple OSS Distributions if (__improbable(!lq->lq_ready)) {
650*bbb1b6f9SApple OSS Distributions enable_preemption();
651*bbb1b6f9SApple OSS Distributions counter_inc(&log_queue_cnt_dropped_off);
652*bbb1b6f9SApple OSS Distributions return false;
653*bbb1b6f9SApple OSS Distributions }
654*bbb1b6f9SApple OSS Distributions
655*bbb1b6f9SApple OSS Distributions boolean_t new_suspend = detect_new_suspend(lq);
656*bbb1b6f9SApple OSS Distributions
657*bbb1b6f9SApple OSS Distributions if (__improbable(lq->lq_mem_state != LQ_MEM_STATE_READY)) {
658*bbb1b6f9SApple OSS Distributions log_queue_mem_reconfigure(lq);
659*bbb1b6f9SApple OSS Distributions } else if (log_queue_needs_memory(lq, new_suspend)) {
660*bbb1b6f9SApple OSS Distributions lq->lq_mem_state = LQ_MEM_STATE_ALLOCATING;
661*bbb1b6f9SApple OSS Distributions order_memory = true;
662*bbb1b6f9SApple OSS Distributions }
663*bbb1b6f9SApple OSS Distributions
664*bbb1b6f9SApple OSS Distributions bool added = log_queue_add_entry(lq, lp, lp_data);
665*bbb1b6f9SApple OSS Distributions enable_preemption();
666*bbb1b6f9SApple OSS Distributions
667*bbb1b6f9SApple OSS Distributions if (order_memory) {
668*bbb1b6f9SApple OSS Distributions log_queue_order_memory(lq);
669*bbb1b6f9SApple OSS Distributions }
670*bbb1b6f9SApple OSS Distributions
671*bbb1b6f9SApple OSS Distributions return added;
672*bbb1b6f9SApple OSS Distributions }
673*bbb1b6f9SApple OSS Distributions
674*bbb1b6f9SApple OSS Distributions __startup_func
675*bbb1b6f9SApple OSS Distributions static size_t
log_queue_init_memory(log_queue_t lq)676*bbb1b6f9SApple OSS Distributions log_queue_init_memory(log_queue_t lq)
677*bbb1b6f9SApple OSS Distributions {
678*bbb1b6f9SApple OSS Distributions lq->lq_cnt_mem_max = log_queue_mem_max_slots();
679*bbb1b6f9SApple OSS Distributions assert(lq->lq_cnt_mem_max <= LQ_MAX_LM_SLOTS);
680*bbb1b6f9SApple OSS Distributions
681*bbb1b6f9SApple OSS Distributions for (size_t i = 0; i < lq->lq_cnt_mem_max; i++) {
682*bbb1b6f9SApple OSS Distributions void *buf = log_queue_buffer_alloc(lq->lq_mem_size);
683*bbb1b6f9SApple OSS Distributions if (!buf) {
684*bbb1b6f9SApple OSS Distributions return i;
685*bbb1b6f9SApple OSS Distributions }
686*bbb1b6f9SApple OSS Distributions counter_inc(&log_queue_cnt_mem_allocated);
687*bbb1b6f9SApple OSS Distributions log_queue_mem_init(lq, i, buf, lq->lq_mem_size);
688*bbb1b6f9SApple OSS Distributions log_queue_mem_enable(lq, i);
689*bbb1b6f9SApple OSS Distributions }
690*bbb1b6f9SApple OSS Distributions
691*bbb1b6f9SApple OSS Distributions return lq->lq_cnt_mem_max;
692*bbb1b6f9SApple OSS Distributions }
693*bbb1b6f9SApple OSS Distributions
694*bbb1b6f9SApple OSS Distributions __startup_func
695*bbb1b6f9SApple OSS Distributions static void
oslog_init_log_queues(void)696*bbb1b6f9SApple OSS Distributions oslog_init_log_queues(void)
697*bbb1b6f9SApple OSS Distributions {
698*bbb1b6f9SApple OSS Distributions if (os_log_disabled()) {
699*bbb1b6f9SApple OSS Distributions printf("Log queues disabled: Logging disabled by ATM\n");
700*bbb1b6f9SApple OSS Distributions return;
701*bbb1b6f9SApple OSS Distributions }
702*bbb1b6f9SApple OSS Distributions
703*bbb1b6f9SApple OSS Distributions if (lq_bootarg_size_order == 0) {
704*bbb1b6f9SApple OSS Distributions printf("Log queues disabled: Zero lq_size_order boot argument\n");
705*bbb1b6f9SApple OSS Distributions return;
706*bbb1b6f9SApple OSS Distributions }
707*bbb1b6f9SApple OSS Distributions
708*bbb1b6f9SApple OSS Distributions lq_bootarg_size_order = MAX(lq_bootarg_size_order, PAGE_SHIFT);
709*bbb1b6f9SApple OSS Distributions lq_bootarg_size_order = MIN(lq_bootarg_size_order, LQ_MAX_SZ_ORDER);
710*bbb1b6f9SApple OSS Distributions
711*bbb1b6f9SApple OSS Distributions lq_bootarg_nslots = MAX(lq_bootarg_nslots, LQ_MIN_ALLOCATED_LM_SLOTS);
712*bbb1b6f9SApple OSS Distributions lq_bootarg_nslots = MIN(lq_bootarg_nslots, LQ_MAX_LM_SLOTS);
713*bbb1b6f9SApple OSS Distributions log_queue_set_max_slots(lq_bootarg_nslots);
714*bbb1b6f9SApple OSS Distributions
715*bbb1b6f9SApple OSS Distributions lq_low_mem_limit = MAX(1 << (lq_bootarg_size_order - LQ_LOW_MEM_SCALE), 1024);
716*bbb1b6f9SApple OSS Distributions
717*bbb1b6f9SApple OSS Distributions unsigned int slot_count = 0;
718*bbb1b6f9SApple OSS Distributions
719*bbb1b6f9SApple OSS Distributions percpu_foreach(lq, oslog_queue) {
720*bbb1b6f9SApple OSS Distributions lq->lq_mem_size_order = lq_bootarg_size_order;
721*bbb1b6f9SApple OSS Distributions lq->lq_mem_size = round_page(logmem_required_size(lq->lq_mem_size_order, LQ_MIN_LOG_SZ_ORDER));
722*bbb1b6f9SApple OSS Distributions lq->lq_mem_handler = thread_call_allocate(log_queue_memory_handler, (thread_call_param_t)lq);
723*bbb1b6f9SApple OSS Distributions slot_count += log_queue_init_memory(lq);
724*bbb1b6f9SApple OSS Distributions STAILQ_INIT(&lq->lq_log_list);
725*bbb1b6f9SApple OSS Distributions STAILQ_INIT(&lq->lq_dispatch_list);
726*bbb1b6f9SApple OSS Distributions lq->lq_ready = true;
727*bbb1b6f9SApple OSS Distributions }
728*bbb1b6f9SApple OSS Distributions
729*bbb1b6f9SApple OSS Distributions printf("Log queues configured: slot count: %u, per-slot size: %u, total size: %u\n",
730*bbb1b6f9SApple OSS Distributions slot_count, (1 << lq_bootarg_size_order),
731*bbb1b6f9SApple OSS Distributions slot_count * (1 << lq_bootarg_size_order));
732*bbb1b6f9SApple OSS Distributions }
733*bbb1b6f9SApple OSS Distributions STARTUP(OSLOG, STARTUP_RANK_SECOND, oslog_init_log_queues);
734*bbb1b6f9SApple OSS Distributions
735*bbb1b6f9SApple OSS Distributions bool
log_queue_log(log_payload_t lp,const void * lp_data,bool stream)736*bbb1b6f9SApple OSS Distributions log_queue_log(log_payload_t lp, const void *lp_data, bool stream)
737*bbb1b6f9SApple OSS Distributions {
738*bbb1b6f9SApple OSS Distributions assert(lp);
739*bbb1b6f9SApple OSS Distributions assert(oslog_is_safe() || startup_phase < STARTUP_SUB_EARLY_BOOT);
740*bbb1b6f9SApple OSS Distributions
741*bbb1b6f9SApple OSS Distributions counter_inc(&log_queue_cnt_received);
742*bbb1b6f9SApple OSS Distributions
743*bbb1b6f9SApple OSS Distributions if (log_payload_send(lp, lp_data, stream)) {
744*bbb1b6f9SApple OSS Distributions counter_inc(&log_queue_cnt_sent);
745*bbb1b6f9SApple OSS Distributions log_queue_dispatch();
746*bbb1b6f9SApple OSS Distributions return true;
747*bbb1b6f9SApple OSS Distributions }
748*bbb1b6f9SApple OSS Distributions counter_inc(&log_queue_cnt_rejected_fh);
749*bbb1b6f9SApple OSS Distributions
750*bbb1b6f9SApple OSS Distributions if (!log_queue_add(lp, lp_data)) {
751*bbb1b6f9SApple OSS Distributions return false;
752*bbb1b6f9SApple OSS Distributions }
753*bbb1b6f9SApple OSS Distributions
754*bbb1b6f9SApple OSS Distributions return true;
755*bbb1b6f9SApple OSS Distributions }
756