author | Jon Tibble <meths@btinternet.com> |
Thu, 26 Apr 2012 21:14:28 +0100 | |
changeset 13725 | 935cf5917cbc |
parent 13720 | 577f82319ed3 |
child 13791 | 786092698997 |
permissions | -rw-r--r-- |
0 | 1 |
/* |
2 |
* CDDL HEADER START |
|
3 |
* |
|
4 |
* The contents of this file are subject to the terms of the |
|
1401
7127a4968f33
6375189 some ON files need copyright update to 2006
mjnelson
parents:
1259
diff
changeset
|
5 |
* Common Development and Distribution License (the "License"). |
7127a4968f33
6375189 some ON files need copyright update to 2006
mjnelson
parents:
1259
diff
changeset
|
6 |
* You may not use this file except in compliance with the License. |
0 | 7 |
* |
8 |
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
|
9 |
* or http://www.opensolaris.org/os/licensing. |
|
10 |
* See the License for the specific language governing permissions |
|
11 |
* and limitations under the License. |
|
12 |
* |
|
13 |
* When distributing Covered Code, include this CDDL HEADER in each |
|
14 |
* file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
|
15 |
* If applicable, add the following below this CDDL HEADER, with the |
|
16 |
* fields enclosed by brackets "[]" replaced with your own identifying |
|
17 |
* information: Portions Copyright [yyyy] [name of copyright owner] |
|
18 |
* |
|
19 |
* CDDL HEADER END |
|
20 |
*/ |
|
1401
7127a4968f33
6375189 some ON files need copyright update to 2006
mjnelson
parents:
1259
diff
changeset
|
21 |
|
0 | 22 |
/* |
12041 | 23 |
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. |
0 | 24 |
*/ |
25 |
||
26 |
#include <sys/types.h> |
|
27 |
#include <sys/param.h> |
|
28 |
#include <sys/varargs.h> |
|
29 |
#include <sys/systm.h> |
|
30 |
#include <sys/cmn_err.h> |
|
31 |
#include <sys/stream.h> |
|
32 |
#include <sys/strsubr.h> |
|
33 |
#include <sys/strsun.h> |
|
34 |
#include <sys/sysmacros.h> |
|
35 |
#include <sys/kmem.h> |
|
36 |
#include <sys/log.h> |
|
37 |
#include <sys/spl.h> |
|
38 |
#include <sys/syslog.h> |
|
39 |
#include <sys/console.h> |
|
40 |
#include <sys/debug.h> |
|
41 |
#include <sys/utsname.h> |
|
42 |
#include <sys/id_space.h> |
|
43 |
#include <sys/zone.h> |
|
44 |
||
45 |
log_zone_t log_global; |
|
46 |
queue_t *log_consq; |
|
47 |
queue_t *log_backlogq; |
|
48 |
queue_t *log_intrq; |
|
49 |
||
50 |
#define LOG_PRISIZE 8 /* max priority size: 7 characters + null */ |
|
51 |
#define LOG_FACSIZE 9 /* max priority size: 8 characters + null */ |
|
52 |
||
53 |
static krwlock_t log_rwlock; |
|
54 |
static int log_rwlock_depth; |
|
55 |
static int log_seq_no[SL_CONSOLE + 1]; |
|
56 |
static stdata_t log_fakestr; |
|
57 |
static id_space_t *log_minorspace; |
|
58 |
static log_t log_backlog; |
|
1259 | 59 |
static struct kmem_cache *log_cons_cache; /* log_t cache */ |
0 | 60 |
|
61 |
static queue_t *log_recentq; |
|
62 |
static queue_t *log_freeq; |
|
63 |
||
64 |
static zone_key_t log_zone_key; |
|
65 |
||
66 |
static char log_overflow_msg[] = "message overflow on /dev/log minor #%d%s\n"; |
|
67 |
||
68 |
static char log_pri[LOG_PRIMASK + 1][LOG_PRISIZE] = { |
|
69 |
"emerg", "alert", "crit", "error", |
|
70 |
"warning", "notice", "info", "debug" |
|
71 |
}; |
|
72 |
||
73 |
static char log_fac[LOG_NFACILITIES + 1][LOG_FACSIZE] = { |
|
74 |
"kern", "user", "mail", "daemon", |
|
75 |
"auth", "syslog", "lpr", "news", |
|
76 |
"uucp", "resv9", "resv10", "resv11", |
|
77 |
"resv12", "audit", "resv14", "cron", |
|
78 |
"local0", "local1", "local2", "local3", |
|
79 |
"local4", "local5", "local6", "local7", |
|
80 |
"unknown" |
|
81 |
}; |
|
1259 | 82 |
static int log_cons_constructor(void *, void *, int); |
83 |
static void log_cons_destructor(void *, void *); |
|
0 | 84 |
|
85 |
/* |
|
86 |
* Get exclusive access to the logging system; this includes all minor |
|
87 |
* devices. We use an rwlock rather than a mutex because hold times |
|
88 |
* are potentially long, so we don't want to waste cycles in adaptive mutex |
|
89 |
* spin (rwlocks always block when contended). Note that we explicitly |
|
90 |
* support recursive calls (e.g. printf() calls foo() calls printf()). |
|
91 |
* |
|
92 |
* Clients may use log_enter() / log_exit() to guarantee that a group |
|
93 |
* of messages is treated atomically (i.e. they appear in order and are |
|
94 |
* not interspersed with any other messages), e.g. for multiline printf(). |
|
95 |
* |
|
96 |
* This could probably be changed to a per-zone lock if contention becomes |
|
97 |
* an issue. |
|
98 |
*/ |
|
99 |
void |
|
100 |
log_enter(void) |
|
101 |
{ |
|
102 |
if (rw_owner(&log_rwlock) != curthread) |
|
103 |
rw_enter(&log_rwlock, RW_WRITER); |
|
104 |
log_rwlock_depth++; |
|
105 |
} |
|
106 |
||
107 |
void |
|
108 |
log_exit(void) |
|
109 |
{ |
|
110 |
if (--log_rwlock_depth == 0) |
|
111 |
rw_exit(&log_rwlock); |
|
112 |
} |
|
113 |
||
114 |
void |
|
115 |
log_flushq(queue_t *q) |
|
116 |
{ |
|
117 |
mblk_t *mp; |
|
118 |
log_t *lp = (log_t *)q->q_ptr; |
|
119 |
||
120 |
/* lp will be NULL if the queue was created via log_makeq */ |
|
6769
c1faa4d16a30
6666472 Network performance regression under heavy load (introduced by 4868863)
ja97890
parents:
5954
diff
changeset
|
121 |
while ((mp = getq_noenab(q, 0)) != NULL) |
0 | 122 |
log_sendmsg(mp, lp == NULL ? GLOBAL_ZONEID : lp->log_zoneid); |
123 |
} |
|
124 |
||
125 |
/* |
|
126 |
* Create a minimal queue with just enough fields filled in to support |
|
127 |
* canput(9F), putq(9F), and getq_noenab(9F). We set QNOENB to ensure |
|
128 |
* that the queue will never be enabled. |
|
129 |
*/ |
|
130 |
static queue_t * |
|
131 |
log_makeq(size_t lowat, size_t hiwat, void *ibc) |
|
132 |
{ |
|
133 |
queue_t *q; |
|
134 |
||
135 |
q = kmem_zalloc(sizeof (queue_t), KM_SLEEP); |
|
136 |
q->q_stream = &log_fakestr; |
|
137 |
q->q_flag = QISDRV | QMTSAFE | QNOENB | QREADR | QUSE; |
|
138 |
q->q_nfsrv = q; |
|
139 |
q->q_lowat = lowat; |
|
140 |
q->q_hiwat = hiwat; |
|
141 |
mutex_init(QLOCK(q), NULL, MUTEX_DRIVER, ibc); |
|
142 |
||
143 |
return (q); |
|
144 |
} |
|
145 |
||
146 |
/* |
|
147 |
* Initialize the log structure for a new zone. |
|
148 |
*/ |
|
149 |
static void * |
|
150 |
log_zoneinit(zoneid_t zoneid) |
|
151 |
{ |
|
152 |
int i; |
|
153 |
log_zone_t *lzp; |
|
154 |
||
155 |
if (zoneid == GLOBAL_ZONEID) |
|
156 |
lzp = &log_global; /* use statically allocated struct */ |
|
157 |
else |
|
158 |
lzp = kmem_zalloc(sizeof (log_zone_t), KM_SLEEP); |
|
159 |
||
160 |
for (i = 0; i < LOG_NUMCLONES; i++) { |
|
161 |
lzp->lz_clones[i].log_minor = |
|
162 |
(minor_t)id_alloc(log_minorspace); |
|
163 |
lzp->lz_clones[i].log_zoneid = zoneid; |
|
164 |
} |
|
165 |
return (lzp); |
|
166 |
} |
|
167 |
||
168 |
/*ARGSUSED*/ |
|
169 |
static void |
|
170 |
log_zonefree(zoneid_t zoneid, void *arg) |
|
171 |
{ |
|
172 |
log_zone_t *lzp = arg; |
|
173 |
int i; |
|
174 |
||
175 |
ASSERT(lzp != &log_global && zoneid != GLOBAL_ZONEID); |
|
176 |
if (lzp == NULL) |
|
177 |
return; |
|
178 |
for (i = 0; i < LOG_NUMCLONES; i++) |
|
179 |
id_free(log_minorspace, lzp->lz_clones[i].log_minor); |
|
180 |
kmem_free(lzp, sizeof (log_zone_t)); |
|
181 |
} |
|
182 |
||
183 |
void |
|
184 |
log_init(void) |
|
185 |
{ |
|
186 |
int log_maxzones; |
|
187 |
||
188 |
/* |
|
189 |
* Create a backlog queue to consume console messages during periods |
|
190 |
* when there is no console reader (e.g. before syslogd(1M) starts). |
|
191 |
*/ |
|
192 |
log_backlogq = log_consq = log_makeq(0, LOG_HIWAT, NULL); |
|
193 |
||
194 |
/* |
|
195 |
* Create a queue to hold free message of size <= LOG_MSGSIZE. |
|
196 |
* Calls from high-level interrupt handlers will do a getq_noenab() |
|
197 |
* from this queue, so its q_lock must be a maximum SPL spin lock. |
|
198 |
*/ |
|
199 |
log_freeq = log_makeq(LOG_MINFREE, LOG_MAXFREE, (void *)ipltospl(SPL8)); |
|
200 |
||
201 |
/* |
|
202 |
* Create a queue for messages from high-level interrupt context. |
|
203 |
* These messages are drained via softcall, or explicitly by panic(). |
|
204 |
*/ |
|
205 |
log_intrq = log_makeq(0, LOG_HIWAT, (void *)ipltospl(SPL8)); |
|
206 |
||
207 |
/* |
|
208 |
* Create a queue to hold the most recent 8K of console messages. |
|
209 |
* Useful for debugging. Required by the "$<msgbuf" adb macro. |
|
210 |
*/ |
|
211 |
log_recentq = log_makeq(0, LOG_RECENTSIZE, NULL); |
|
212 |
||
213 |
/* |
|
214 |
* Create an id space for clone devices opened via /dev/log. |
|
215 |
* Need to limit the number of zones to avoid exceeding the |
|
216 |
* available minor number space. |
|
217 |
*/ |
|
218 |
log_maxzones = (L_MAXMIN32 - LOG_LOGMIN) / LOG_NUMCLONES - 1; |
|
219 |
if (log_maxzones < maxzones) |
|
220 |
maxzones = log_maxzones; |
|
221 |
log_minorspace = id_space_create("logminor_space", LOG_LOGMIN + 1, |
|
222 |
L_MAXMIN32); |
|
223 |
/* |
|
224 |
* Put ourselves on the ZSD list. Note that zones have not been |
|
225 |
* initialized yet, but our constructor will be called on the global |
|
226 |
* zone when they are. |
|
227 |
*/ |
|
228 |
zone_key_create(&log_zone_key, log_zoneinit, NULL, log_zonefree); |
|
229 |
||
230 |
/* |
|
231 |
* Initialize backlog structure. |
|
232 |
*/ |
|
233 |
log_backlog.log_zoneid = GLOBAL_ZONEID; |
|
234 |
log_backlog.log_minor = LOG_BACKLOG; |
|
235 |
||
1259 | 236 |
/* Allocate kmem cache for conslog's log structures */ |
237 |
log_cons_cache = kmem_cache_create("log_cons_cache", |
|
238 |
sizeof (struct log), 0, log_cons_constructor, log_cons_destructor, |
|
239 |
NULL, NULL, NULL, 0); |
|
0 | 240 |
|
241 |
/* |
|
242 |
* Let the logging begin. |
|
243 |
*/ |
|
244 |
log_update(&log_backlog, log_backlogq, SL_CONSOLE, log_console); |
|
245 |
||
246 |
/* |
|
247 |
* Now that logging is enabled, emit the SunOS banner. |
|
248 |
*/ |
|
13725
935cf5917cbc
Pull in upstream to 13676:98ca40df9171
Jon Tibble <meths@btinternet.com>
parents:
13720
diff
changeset
|
249 |
printf("\rOpenIndiana Build %s %u-bit (illumos 13676:98ca40df9171)\n", |
13433
e3d65601e194
Rebranding for boot banner
Alasdair Lumsden <al@everycity.co.uk>
parents:
12041
diff
changeset
|
250 |
utsname.version, NBBY * (uint_t)sizeof (void *)); |
e3d65601e194
Rebranding for boot banner
Alasdair Lumsden <al@everycity.co.uk>
parents:
12041
diff
changeset
|
251 |
printf("SunOS Release %s - Copyright 1983-2010 Oracle and/or its " |
e3d65601e194
Rebranding for boot banner
Alasdair Lumsden <al@everycity.co.uk>
parents:
12041
diff
changeset
|
252 |
"affiliates.\n", utsname.release); |
e3d65601e194
Rebranding for boot banner
Alasdair Lumsden <al@everycity.co.uk>
parents:
12041
diff
changeset
|
253 |
printf("All rights reserved. Use is subject to license terms.\n"); |
e3d65601e194
Rebranding for boot banner
Alasdair Lumsden <al@everycity.co.uk>
parents:
12041
diff
changeset
|
254 |
|
0 | 255 |
#ifdef DEBUG |
256 |
printf("DEBUG enabled\n"); |
|
257 |
#endif |
|
258 |
} |
|
259 |
||
260 |
/* |
|
1259 | 261 |
* Allocate a log device corresponding to supplied device type. |
262 |
* Both devices are clonable. /dev/log devices are allocated per zone. |
|
263 |
* /dev/conslog devices are allocated from kmem cache. |
|
0 | 264 |
*/ |
265 |
log_t * |
|
266 |
log_alloc(minor_t type) |
|
267 |
{ |
|
268 |
zone_t *zptr = curproc->p_zone; |
|
269 |
log_zone_t *lzp; |
|
270 |
log_t *lp; |
|
271 |
int i; |
|
1259 | 272 |
minor_t minor; |
0 | 273 |
|
274 |
if (type == LOG_CONSMIN) { |
|
275 |
||
1259 | 276 |
/* |
277 |
* Return a write-only /dev/conslog device. |
|
278 |
* No point allocating log_t until there's a free minor number. |
|
279 |
*/ |
|
280 |
minor = (minor_t)id_alloc(log_minorspace); |
|
281 |
lp = kmem_cache_alloc(log_cons_cache, KM_SLEEP); |
|
282 |
lp->log_minor = minor; |
|
283 |
return (lp); |
|
284 |
} else { |
|
285 |
ASSERT(type == LOG_LOGMIN); |
|
0 | 286 |
|
1259 | 287 |
lzp = zone_getspecific(log_zone_key, zptr); |
288 |
ASSERT(lzp != NULL); |
|
0 | 289 |
|
1259 | 290 |
/* search for an available /dev/log device for the zone */ |
291 |
for (i = LOG_LOGMINIDX; i <= LOG_LOGMAXIDX; i++) { |
|
292 |
lp = &lzp->lz_clones[i]; |
|
293 |
if (lp->log_inuse == 0) |
|
294 |
break; |
|
295 |
} |
|
296 |
if (i > LOG_LOGMAXIDX) |
|
297 |
lp = NULL; |
|
298 |
else |
|
299 |
/* Indicate which device type */ |
|
300 |
lp->log_major = LOG_LOGMIN; |
|
301 |
return (lp); |
|
0 | 302 |
} |
1259 | 303 |
} |
304 |
||
305 |
void |
|
306 |
log_free(log_t *lp) |
|
307 |
{ |
|
308 |
id_free(log_minorspace, lp->log_minor); |
|
309 |
kmem_cache_free(log_cons_cache, lp); |
|
0 | 310 |
} |
311 |
||
312 |
/* |
|
313 |
* Move console messages from src to dst. The time of day isn't known |
|
314 |
* early in boot, so fix up the message timestamps if necessary. |
|
315 |
*/ |
|
316 |
static void |
|
317 |
log_conswitch(log_t *src, log_t *dst) |
|
318 |
{ |
|
319 |
mblk_t *mp; |
|
320 |
mblk_t *hmp = NULL; |
|
321 |
mblk_t *tmp = NULL; |
|
322 |
log_ctl_t *hlc; |
|
323 |
||
6769
c1faa4d16a30
6666472 Network performance regression under heavy load (introduced by 4868863)
ja97890
parents:
5954
diff
changeset
|
324 |
while ((mp = getq_noenab(src->log_q, 0)) != NULL) { |
0 | 325 |
log_ctl_t *lc = (log_ctl_t *)mp->b_rptr; |
326 |
lc->flags |= SL_LOGONLY; |
|
327 |
||
328 |
/* |
|
4123 | 329 |
* The ttime is written with 0 in log_sensmsg() only when |
2771
3414606edb08
6464408 Timestamp on /var/adm/messages is wrong after 248 days
kk112340
parents:
1401
diff
changeset
|
330 |
* good gethrestime_sec() data is not available to store in |
3414606edb08
6464408 Timestamp on /var/adm/messages is wrong after 248 days
kk112340
parents:
1401
diff
changeset
|
331 |
* the log_ctl_t in the early boot phase. |
0 | 332 |
*/ |
2771
3414606edb08
6464408 Timestamp on /var/adm/messages is wrong after 248 days
kk112340
parents:
1401
diff
changeset
|
333 |
if (lc->ttime == 0) { |
0 | 334 |
/* |
335 |
* Look ahead to first early boot message with time. |
|
336 |
*/ |
|
337 |
if (hmp) { |
|
338 |
tmp->b_next = mp; |
|
339 |
tmp = mp; |
|
340 |
} else |
|
341 |
hmp = tmp = mp; |
|
342 |
continue; |
|
343 |
} |
|
344 |
||
345 |
while (hmp) { |
|
346 |
tmp = hmp->b_next; |
|
347 |
hmp->b_next = NULL; |
|
348 |
hlc = (log_ctl_t *)hmp->b_rptr; |
|
349 |
/* |
|
350 |
* Calculate hrestime for an early log message with |
|
351 |
* an invalid time stamp. We know: |
|
352 |
* - the lbolt of the invalid time stamp. |
|
353 |
* - the hrestime and lbolt of the first valid |
|
354 |
* time stamp. |
|
355 |
*/ |
|
356 |
hlc->ttime = lc->ttime - (lc->ltime - hlc->ltime) / hz; |
|
357 |
(void) putq(dst->log_q, hmp); |
|
358 |
hmp = tmp; |
|
359 |
} |
|
360 |
(void) putq(dst->log_q, mp); |
|
361 |
} |
|
362 |
while (hmp) { |
|
363 |
tmp = hmp->b_next; |
|
364 |
hmp->b_next = NULL; |
|
365 |
hlc = (log_ctl_t *)hmp->b_rptr; |
|
11066
cebb50cbe4f9
PSARC/2009/396 Tickless Kernel Architecture / lbolt decoupling
Rafael Vanoni <rafael.vanoni@sun.com>
parents:
8576
diff
changeset
|
366 |
hlc->ttime = gethrestime_sec() - |
cebb50cbe4f9
PSARC/2009/396 Tickless Kernel Architecture / lbolt decoupling
Rafael Vanoni <rafael.vanoni@sun.com>
parents:
8576
diff
changeset
|
367 |
(ddi_get_lbolt() - hlc->ltime) / hz; |
0 | 368 |
(void) putq(dst->log_q, hmp); |
369 |
hmp = tmp; |
|
370 |
} |
|
371 |
dst->log_overflow = src->log_overflow; |
|
372 |
src->log_flags = 0; |
|
373 |
dst->log_flags = SL_CONSOLE; |
|
374 |
log_consq = dst->log_q; |
|
375 |
} |
|
376 |
||
377 |
/* |
|
378 |
* Set the fields in the 'target' clone to the specified values. |
|
379 |
* Then, look at all clones to determine which message types are |
|
380 |
* currently active and which clone is the primary console queue. |
|
381 |
* If the primary console queue changes to or from the backlog |
|
382 |
* queue, copy all messages from backlog to primary or vice versa. |
|
383 |
*/ |
|
384 |
void |
|
385 |
log_update(log_t *target, queue_t *q, short flags, log_filter_t *filter) |
|
386 |
{ |
|
387 |
log_t *lp; |
|
388 |
short active = SL_CONSOLE; |
|
389 |
zone_t *zptr = NULL; |
|
390 |
log_zone_t *lzp; |
|
391 |
zoneid_t zoneid = target->log_zoneid; |
|
392 |
int i; |
|
393 |
||
394 |
log_enter(); |
|
395 |
||
396 |
if (q != NULL) |
|
397 |
target->log_q = q; |
|
398 |
target->log_wanted = filter; |
|
399 |
target->log_flags = flags; |
|
400 |
target->log_overflow = 0; |
|
401 |
||
402 |
/* |
|
403 |
* Need to special case the global zone here since this may be |
|
404 |
* called before zone_init. |
|
405 |
*/ |
|
406 |
if (zoneid == GLOBAL_ZONEID) { |
|
407 |
lzp = &log_global; |
|
408 |
} else if ((zptr = zone_find_by_id(zoneid)) == NULL) { |
|
409 |
log_exit(); |
|
410 |
return; /* zone is being destroyed, ignore update */ |
|
411 |
} else { |
|
412 |
lzp = zone_getspecific(log_zone_key, zptr); |
|
413 |
} |
|
414 |
ASSERT(lzp != NULL); |
|
415 |
for (i = LOG_LOGMAXIDX; i >= LOG_LOGMINIDX; i--) { |
|
416 |
lp = &lzp->lz_clones[i]; |
|
417 |
if (zoneid == GLOBAL_ZONEID && (lp->log_flags & SL_CONSOLE)) |
|
418 |
log_consq = lp->log_q; |
|
419 |
active |= lp->log_flags; |
|
420 |
} |
|
421 |
lzp->lz_active = active; |
|
422 |
||
423 |
if (zptr) |
|
424 |
zone_rele(zptr); |
|
425 |
||
426 |
if (log_consq == target->log_q) { |
|
427 |
if (flags & SL_CONSOLE) |
|
428 |
log_conswitch(&log_backlog, target); |
|
429 |
else |
|
430 |
log_conswitch(target, &log_backlog); |
|
431 |
} |
|
432 |
target->log_q = q; |
|
433 |
||
434 |
log_exit(); |
|
435 |
} |
|
436 |
||
437 |
/*ARGSUSED*/ |
|
438 |
int |
|
439 |
log_error(log_t *lp, log_ctl_t *lc) |
|
440 |
{ |
|
441 |
if ((lc->pri & LOG_FACMASK) == LOG_KERN) |
|
442 |
lc->pri = LOG_KERN | LOG_ERR; |
|
443 |
return (1); |
|
444 |
} |
|
445 |
||
446 |
int |
|
447 |
log_trace(log_t *lp, log_ctl_t *lc) |
|
448 |
{ |
|
449 |
trace_ids_t *tid = (trace_ids_t *)lp->log_data->b_rptr; |
|
450 |
trace_ids_t *tidend = (trace_ids_t *)lp->log_data->b_wptr; |
|
451 |
||
452 |
/* |
|
453 |
* We use `tid + 1 <= tidend' here rather than the more traditional |
|
454 |
* `tid < tidend', since the former ensures that there's at least |
|
455 |
* `sizeof (trace_ids_t)' bytes available before executing the |
|
456 |
* loop, whereas the latter only ensures that there's a single byte. |
|
457 |
*/ |
|
458 |
for (; tid + 1 <= tidend; tid++) { |
|
459 |
if (tid->ti_level < lc->level && tid->ti_level >= 0) |
|
460 |
continue; |
|
461 |
if (tid->ti_mid != lc->mid && tid->ti_mid >= 0) |
|
462 |
continue; |
|
463 |
if (tid->ti_sid != lc->sid && tid->ti_sid >= 0) |
|
464 |
continue; |
|
465 |
if ((lc->pri & LOG_FACMASK) == LOG_KERN) |
|
466 |
lc->pri = LOG_KERN | LOG_DEBUG; |
|
467 |
return (1); |
|
468 |
} |
|
469 |
return (0); |
|
470 |
} |
|
471 |
||
472 |
/*ARGSUSED*/ |
|
473 |
int |
|
474 |
log_console(log_t *lp, log_ctl_t *lc) |
|
475 |
{ |
|
476 |
if ((lc->pri & LOG_FACMASK) == LOG_KERN) { |
|
477 |
if (lc->flags & SL_FATAL) |
|
478 |
lc->pri = LOG_KERN | LOG_CRIT; |
|
479 |
else if (lc->flags & SL_ERROR) |
|
480 |
lc->pri = LOG_KERN | LOG_ERR; |
|
481 |
else if (lc->flags & SL_WARN) |
|
482 |
lc->pri = LOG_KERN | LOG_WARNING; |
|
483 |
else if (lc->flags & SL_NOTE) |
|
484 |
lc->pri = LOG_KERN | LOG_NOTICE; |
|
485 |
else if (lc->flags & SL_TRACE) |
|
486 |
lc->pri = LOG_KERN | LOG_DEBUG; |
|
487 |
else |
|
488 |
lc->pri = LOG_KERN | LOG_INFO; |
|
489 |
} |
|
490 |
return (1); |
|
491 |
} |
|
492 |
||
493 |
mblk_t * |
|
494 |
log_makemsg(int mid, int sid, int level, int sl, int pri, void *msg, |
|
495 |
size_t size, int on_intr) |
|
496 |
{ |
|
497 |
mblk_t *mp = NULL; |
|
498 |
mblk_t *mp2; |
|
499 |
log_ctl_t *lc; |
|
500 |
||
501 |
if (size <= LOG_MSGSIZE && |
|
502 |
(on_intr || log_freeq->q_count > log_freeq->q_lowat)) |
|
6769
c1faa4d16a30
6666472 Network performance regression under heavy load (introduced by 4868863)
ja97890
parents:
5954
diff
changeset
|
503 |
mp = getq_noenab(log_freeq, 0); |
0 | 504 |
|
505 |
if (mp == NULL) { |
|
506 |
if (on_intr || |
|
507 |
(mp = allocb(sizeof (log_ctl_t), BPRI_HI)) == NULL || |
|
508 |
(mp2 = allocb(MAX(size, LOG_MSGSIZE), BPRI_HI)) == NULL) { |
|
509 |
freemsg(mp); |
|
510 |
return (NULL); |
|
511 |
} |
|
512 |
DB_TYPE(mp) = M_PROTO; |
|
513 |
mp->b_wptr += sizeof (log_ctl_t); |
|
514 |
mp->b_cont = mp2; |
|
515 |
} else { |
|
516 |
mp2 = mp->b_cont; |
|
517 |
mp2->b_wptr = mp2->b_rptr; |
|
518 |
} |
|
519 |
||
520 |
lc = (log_ctl_t *)mp->b_rptr; |
|
521 |
lc->mid = mid; |
|
522 |
lc->sid = sid; |
|
523 |
lc->level = level; |
|
524 |
lc->flags = sl; |
|
525 |
lc->pri = pri; |
|
526 |
||
527 |
bcopy(msg, mp2->b_wptr, size - 1); |
|
528 |
mp2->b_wptr[size - 1] = '\0'; |
|
529 |
mp2->b_wptr += strlen((char *)mp2->b_wptr) + 1; |
|
530 |
||
531 |
return (mp); |
|
532 |
} |
|
533 |
||
534 |
void |
|
535 |
log_freemsg(mblk_t *mp) |
|
536 |
{ |
|
537 |
mblk_t *mp2 = mp->b_cont; |
|
538 |
||
539 |
ASSERT(MBLKL(mp) == sizeof (log_ctl_t)); |
|
540 |
ASSERT(mp2->b_rptr == mp2->b_datap->db_base); |
|
541 |
||
542 |
if ((log_freeq->q_flag & QFULL) == 0 && |
|
543 |
MBLKL(mp2) <= LOG_MSGSIZE && MBLKSIZE(mp2) >= LOG_MSGSIZE) |
|
544 |
(void) putq(log_freeq, mp); |
|
545 |
else |
|
546 |
freemsg(mp); |
|
547 |
} |
|
548 |
||
549 |
void |
|
550 |
log_sendmsg(mblk_t *mp, zoneid_t zoneid) |
|
551 |
{ |
|
552 |
log_t *lp; |
|
553 |
char *src, *dst; |
|
554 |
mblk_t *mp2 = mp->b_cont; |
|
555 |
log_ctl_t *lc = (log_ctl_t *)mp->b_rptr; |
|
556 |
int flags, fac; |
|
557 |
off_t facility = 0; |
|
558 |
off_t body = 0; |
|
559 |
zone_t *zptr = NULL; |
|
560 |
log_zone_t *lzp; |
|
561 |
int i; |
|
562 |
int backlog; |
|
563 |
||
564 |
/* |
|
565 |
* Need to special case the global zone here since this may be |
|
566 |
* called before zone_init. |
|
567 |
*/ |
|
568 |
if (zoneid == GLOBAL_ZONEID) { |
|
569 |
lzp = &log_global; |
|
570 |
} else if ((zptr = zone_find_by_id(zoneid)) == NULL) { |
|
571 |
/* specified zone doesn't exist, free message and return */ |
|
572 |
log_freemsg(mp); |
|
573 |
return; |
|
574 |
} else { |
|
575 |
lzp = zone_getspecific(log_zone_key, zptr); |
|
576 |
} |
|
577 |
ASSERT(lzp != NULL); |
|
578 |
||
579 |
if ((lc->flags & lzp->lz_active) == 0) { |
|
580 |
if (zptr) |
|
581 |
zone_rele(zptr); |
|
582 |
log_freemsg(mp); |
|
583 |
return; |
|
584 |
} |
|
585 |
||
586 |
if (panicstr) { |
|
587 |
/* |
|
588 |
* Raise the console queue's q_hiwat to ensure that we |
|
589 |
* capture all panic messages. |
|
590 |
*/ |
|
591 |
log_consq->q_hiwat = 2 * LOG_HIWAT; |
|
592 |
log_consq->q_flag &= ~QFULL; |
|
593 |
||
594 |
/* Message was created while panicking. */ |
|
595 |
lc->flags |= SL_PANICMSG; |
|
596 |
} |
|
597 |
||
598 |
src = (char *)mp2->b_rptr; |
|
599 |
dst = strstr(src, "FACILITY_AND_PRIORITY] "); |
|
600 |
if (dst != NULL) { |
|
601 |
facility = dst - src; |
|
602 |
body = facility + 23; /* strlen("FACILITY_AND_PRIORITY] ") */ |
|
603 |
} |
|
604 |
||
605 |
log_enter(); |
|
606 |
||
2771
3414606edb08
6464408 Timestamp on /var/adm/messages is wrong after 248 days
kk112340
parents:
1401
diff
changeset
|
607 |
/* |
4123 | 608 |
* In the early boot phase hrestime is invalid, then timechanged is 0. |
609 |
* If hrestime is not valid, the ttime is set to 0 here and the correct |
|
610 |
* ttime is calculated in log_conswitch() later. The log_conswitch() |
|
611 |
* calculation to determine the correct ttime does not use ttime data |
|
612 |
* from these log_ctl_t structures; it only uses ttime from log_ctl_t's |
|
613 |
* that contain good data. |
|
614 |
* |
|
2771
3414606edb08
6464408 Timestamp on /var/adm/messages is wrong after 248 days
kk112340
parents:
1401
diff
changeset
|
615 |
*/ |
11066
cebb50cbe4f9
PSARC/2009/396 Tickless Kernel Architecture / lbolt decoupling
Rafael Vanoni <rafael.vanoni@sun.com>
parents:
8576
diff
changeset
|
616 |
lc->ltime = ddi_get_lbolt(); |
4123 | 617 |
if (timechanged) { |
2771
3414606edb08
6464408 Timestamp on /var/adm/messages is wrong after 248 days
kk112340
parents:
1401
diff
changeset
|
618 |
lc->ttime = gethrestime_sec(); |
3414606edb08
6464408 Timestamp on /var/adm/messages is wrong after 248 days
kk112340
parents:
1401
diff
changeset
|
619 |
} else { |
3414606edb08
6464408 Timestamp on /var/adm/messages is wrong after 248 days
kk112340
parents:
1401
diff
changeset
|
620 |
lc->ttime = 0; |
3414606edb08
6464408 Timestamp on /var/adm/messages is wrong after 248 days
kk112340
parents:
1401
diff
changeset
|
621 |
} |
0 | 622 |
|
623 |
flags = lc->flags & lzp->lz_active; |
|
624 |
log_seq_no[flags & SL_ERROR]++; |
|
625 |
log_seq_no[flags & SL_TRACE]++; |
|
626 |
log_seq_no[flags & SL_CONSOLE]++; |
|
627 |
||
628 |
/* |
|
629 |
* If this is in the global zone, start with the backlog, then |
|
630 |
* walk through the clone logs. If not, just do the clone logs. |
|
631 |
*/ |
|
632 |
backlog = (zoneid == GLOBAL_ZONEID); |
|
633 |
i = LOG_LOGMINIDX; |
|
634 |
while (i <= LOG_LOGMAXIDX) { |
|
635 |
if (backlog) { |
|
636 |
/* |
|
637 |
* Do the backlog this time, then start on the |
|
638 |
* others. |
|
639 |
*/ |
|
640 |
backlog = 0; |
|
641 |
lp = &log_backlog; |
|
642 |
} else { |
|
643 |
lp = &lzp->lz_clones[i++]; |
|
644 |
} |
|
645 |
||
646 |
if ((lp->log_flags & flags) && lp->log_wanted(lp, lc)) { |
|
647 |
if (canput(lp->log_q)) { |
|
648 |
lp->log_overflow = 0; |
|
649 |
lc->seq_no = log_seq_no[lp->log_flags]; |
|
650 |
if ((mp2 = copymsg(mp)) == NULL) |
|
651 |
break; |
|
652 |
if (facility != 0) { |
|
653 |
src = (char *)mp2->b_cont->b_rptr; |
|
654 |
dst = src + facility; |
|
655 |
fac = (lc->pri & LOG_FACMASK) >> 3; |
|
656 |
dst += snprintf(dst, |
|
657 |
LOG_FACSIZE + LOG_PRISIZE, "%s.%s", |
|
658 |
log_fac[MIN(fac, LOG_NFACILITIES)], |
|
659 |
log_pri[lc->pri & LOG_PRIMASK]); |
|
660 |
src += body - 2; /* copy "] " too */ |
|
661 |
while (*src != '\0') |
|
662 |
*dst++ = *src++; |
|
663 |
*dst++ = '\0'; |
|
664 |
mp2->b_cont->b_wptr = (uchar_t *)dst; |
|
665 |
} |
|
666 |
(void) putq(lp->log_q, mp2); |
|
667 |
} else if (++lp->log_overflow == 1) { |
|
668 |
if (lp->log_q == log_consq) { |
|
669 |
console_printf(log_overflow_msg, |
|
670 |
lp->log_minor, |
|
671 |
" -- is syslogd(1M) running?"); |
|
672 |
} else { |
|
673 |
printf(log_overflow_msg, |
|
674 |
lp->log_minor, ""); |
|
675 |
} |
|
676 |
} |
|
677 |
} |
|
678 |
} |
|
679 |
||
680 |
if (zptr) |
|
681 |
zone_rele(zptr); |
|
682 |
||
683 |
if ((flags & SL_CONSOLE) && (lc->pri & LOG_FACMASK) == LOG_KERN) { |
|
684 |
if ((mp2 == NULL || log_consq == log_backlogq || panicstr) && |
|
685 |
(lc->flags & SL_LOGONLY) == 0) |
|
686 |
console_printf("%s", (char *)mp->b_cont->b_rptr + body); |
|
687 |
if ((lc->flags & SL_CONSONLY) == 0 && |
|
688 |
(mp2 = copymsg(mp)) != NULL) { |
|
689 |
mp2->b_cont->b_rptr += body; |
|
690 |
if (log_recentq->q_flag & QFULL) |
|
6769
c1faa4d16a30
6666472 Network performance regression under heavy load (introduced by 4868863)
ja97890
parents:
5954
diff
changeset
|
691 |
freemsg(getq_noenab(log_recentq, 0)); |
0 | 692 |
(void) putq(log_recentq, mp2); |
693 |
} |
|
694 |
} |
|
695 |
||
696 |
log_freemsg(mp); |
|
697 |
||
698 |
log_exit(); |
|
699 |
} |
|
700 |
||
701 |
/* |
|
702 |
* Print queued messages to console. |
|
703 |
*/ |
|
704 |
void |
|
705 |
log_printq(queue_t *qfirst) |
|
706 |
{ |
|
707 |
mblk_t *mp; |
|
708 |
queue_t *q, *qlast; |
|
709 |
char *cp, *msgp; |
|
710 |
log_ctl_t *lc; |
|
711 |
||
712 |
/* |
|
713 |
* Look ahead to first queued message in the stream. |
|
714 |
*/ |
|
715 |
qlast = NULL; |
|
716 |
do { |
|
717 |
for (q = qfirst; q->q_next != qlast; q = q->q_next) |
|
718 |
continue; |
|
719 |
for (mp = q->q_first; mp != NULL; mp = mp->b_next) { |
|
720 |
lc = (log_ctl_t *)mp->b_rptr; |
|
721 |
/* |
|
722 |
* Check if message is already displayed at |
|
723 |
* /dev/console. |
|
724 |
*/ |
|
725 |
if (lc->flags & SL_PANICMSG) |
|
726 |
continue; |
|
727 |
||
728 |
cp = (char *)mp->b_cont->b_rptr; |
|
729 |
||
730 |
/* Strip off the message ID. */ |
|
731 |
if ((msgp = strstr(cp, "[ID ")) != NULL && |
|
732 |
(msgp = strstr(msgp, "] ")) != NULL) { |
|
733 |
cp = msgp + 2; |
|
734 |
} |
|
735 |
||
736 |
/* |
|
737 |
* Using console_printf instead of printf to avoid |
|
738 |
* queueing messages to log_consq. |
|
739 |
*/ |
|
740 |
console_printf("%s", cp); |
|
741 |
} |
|
742 |
} while ((qlast = q) != qfirst); |
|
743 |
} |
|
1259 | 744 |
|
745 |
/* ARGSUSED */ |
|
746 |
static int |
|
747 |
log_cons_constructor(void *buf, void *cdrarg, int kmflags) |
|
748 |
{ |
|
749 |
struct log *lp = buf; |
|
750 |
||
751 |
lp->log_zoneid = GLOBAL_ZONEID; |
|
752 |
lp->log_major = LOG_CONSMIN; /* Indicate which device type */ |
|
753 |
lp->log_data = NULL; |
|
754 |
return (0); |
|
755 |
} |
|
756 |
||
757 |
/* ARGSUSED */ |
|
758 |
static void |
|
759 |
log_cons_destructor(void *buf, void *cdrarg) |
|
760 |
{ |
|
761 |
struct log *lp = buf; |
|
762 |
||
763 |
ASSERT(lp->log_zoneid == GLOBAL_ZONEID); |
|
764 |
ASSERT(lp->log_major == LOG_CONSMIN); |
|
765 |
ASSERT(lp->log_data == NULL); |
|
766 |
} |