4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
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.
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]
23 * Copyright (c) 2013 Gary Mills
24 * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
27 #include <sys/types.h>
28 #include <sys/param.h>
29 #include <sys/varargs.h>
30 #include <sys/systm.h>
31 #include <sys/cmn_err.h>
32 #include <sys/stream.h>
33 #include <sys/strsubr.h>
34 #include <sys/strsun.h>
35 #include <sys/sysmacros.h>
39 #include <sys/syslog.h>
40 #include <sys/console.h>
41 #include <sys/debug.h>
42 #include <sys/utsname.h>
43 #include <sys/id_space.h>
46 log_zone_t log_global
;
48 queue_t
*log_backlogq
;
51 #define LOG_PRISIZE 8 /* max priority size: 7 characters + null */
52 #define LOG_FACSIZE 9 /* max priority size: 8 characters + null */
54 static krwlock_t log_rwlock
;
55 static int log_rwlock_depth
;
56 static int log_seq_no
[SL_CONSOLE
+ 1];
57 static stdata_t log_fakestr
;
58 static id_space_t
*log_minorspace
;
59 static log_t log_backlog
;
60 static struct kmem_cache
*log_cons_cache
; /* log_t cache */
62 static queue_t
*log_recentq
;
63 static queue_t
*log_freeq
;
65 static zone_key_t log_zone_key
;
67 static char log_overflow_msg
[] = "message overflow on /dev/log minor #%d%s\n";
69 static char log_pri
[LOG_PRIMASK
+ 1][LOG_PRISIZE
] = {
70 "emerg", "alert", "crit", "error",
71 "warning", "notice", "info", "debug"
74 static char log_fac
[LOG_NFACILITIES
+ 1][LOG_FACSIZE
] = {
75 "kern", "user", "mail", "daemon",
76 "auth", "syslog", "lpr", "news",
77 "uucp", "altcron", "authpriv", "ftp",
78 "ntp", "audit", "console", "cron",
79 "local0", "local1", "local2", "local3",
80 "local4", "local5", "local6", "local7",
83 static int log_cons_constructor(void *, void *, int);
84 static void log_cons_destructor(void *, void *);
87 * Get exclusive access to the logging system; this includes all minor
88 * devices. We use an rwlock rather than a mutex because hold times
89 * are potentially long, so we don't want to waste cycles in adaptive mutex
90 * spin (rwlocks always block when contended). Note that we explicitly
91 * support recursive calls (e.g. printf() calls foo() calls printf()).
93 * Clients may use log_enter() / log_exit() to guarantee that a group
94 * of messages is treated atomically (i.e. they appear in order and are
95 * not interspersed with any other messages), e.g. for multiline printf().
97 * This could probably be changed to a per-zone lock if contention becomes
103 if (rw_owner(&log_rwlock
) != curthread
)
104 rw_enter(&log_rwlock
, RW_WRITER
);
111 if (--log_rwlock_depth
== 0)
112 rw_exit(&log_rwlock
);
116 log_flushq(queue_t
*q
)
119 log_t
*lp
= (log_t
*)q
->q_ptr
;
121 /* lp will be NULL if the queue was created via log_makeq */
122 while ((mp
= getq_noenab(q
, 0)) != NULL
)
123 log_sendmsg(mp
, lp
== NULL
? GLOBAL_ZONEID
: lp
->log_zoneid
);
127 * Create a minimal queue with just enough fields filled in to support
128 * canput(9F), putq(9F), and getq_noenab(9F). We set QNOENB to ensure
129 * that the queue will never be enabled.
132 log_makeq(size_t lowat
, size_t hiwat
, void *ibc
)
136 q
= kmem_zalloc(sizeof (queue_t
), KM_SLEEP
);
137 q
->q_stream
= &log_fakestr
;
138 q
->q_flag
= QISDRV
| QMTSAFE
| QNOENB
| QREADR
| QUSE
;
142 mutex_init(QLOCK(q
), NULL
, MUTEX_DRIVER
, ibc
);
148 * Initialize the log structure for a new zone.
151 log_zoneinit(zoneid_t zoneid
)
156 if (zoneid
== GLOBAL_ZONEID
)
157 lzp
= &log_global
; /* use statically allocated struct */
159 lzp
= kmem_zalloc(sizeof (log_zone_t
), KM_SLEEP
);
161 for (i
= 0; i
< LOG_NUMCLONES
; i
++) {
162 lzp
->lz_clones
[i
].log_minor
=
163 (minor_t
)id_alloc(log_minorspace
);
164 lzp
->lz_clones
[i
].log_zoneid
= zoneid
;
171 log_zonefree(zoneid_t zoneid
, void *arg
)
173 log_zone_t
*lzp
= arg
;
176 ASSERT(lzp
!= &log_global
&& zoneid
!= GLOBAL_ZONEID
);
179 for (i
= 0; i
< LOG_NUMCLONES
; i
++)
180 id_free(log_minorspace
, lzp
->lz_clones
[i
].log_minor
);
181 kmem_free(lzp
, sizeof (log_zone_t
));
190 * Create a backlog queue to consume console messages during periods
191 * when there is no console reader (e.g. before syslogd(1M) starts).
193 log_backlogq
= log_consq
= log_makeq(0, LOG_HIWAT
, NULL
);
196 * Create a queue to hold free message of size <= LOG_MSGSIZE.
197 * Calls from high-level interrupt handlers will do a getq_noenab()
198 * from this queue, so its q_lock must be a maximum SPL spin lock.
200 log_freeq
= log_makeq(LOG_MINFREE
, LOG_MAXFREE
, (void *)ipltospl(SPL8
));
203 * Create a queue for messages from high-level interrupt context.
204 * These messages are drained via softcall, or explicitly by panic().
206 log_intrq
= log_makeq(0, LOG_HIWAT
, (void *)ipltospl(SPL8
));
209 * Create a queue to hold the most recent 8K of console messages.
210 * Useful for debugging. Required by the "$<msgbuf" adb macro.
212 log_recentq
= log_makeq(0, LOG_RECENTSIZE
, NULL
);
215 * Create an id space for clone devices opened via /dev/log.
216 * Need to limit the number of zones to avoid exceeding the
217 * available minor number space.
219 log_maxzones
= (L_MAXMIN32
- LOG_LOGMIN
) / LOG_NUMCLONES
- 1;
220 if (log_maxzones
< maxzones
)
221 maxzones
= log_maxzones
;
222 log_minorspace
= id_space_create("logminor_space", LOG_LOGMIN
+ 1,
225 * Put ourselves on the ZSD list. Note that zones have not been
226 * initialized yet, but our constructor will be called on the global
227 * zone when they are.
229 zone_key_create(&log_zone_key
, log_zoneinit
, NULL
, log_zonefree
);
232 * Initialize backlog structure.
234 log_backlog
.log_zoneid
= GLOBAL_ZONEID
;
235 log_backlog
.log_minor
= LOG_BACKLOG
;
237 /* Allocate kmem cache for conslog's log structures */
238 log_cons_cache
= kmem_cache_create("log_cons_cache",
239 sizeof (struct log
), 0, log_cons_constructor
, log_cons_destructor
,
240 NULL
, NULL
, NULL
, 0);
243 * Let the logging begin.
245 log_update(&log_backlog
, log_backlogq
, SL_CONSOLE
, log_console
);
248 * Now that logging is enabled, emit the boot banner.
250 printf("\rUnleashed %s %u-bit\n",
251 utsname
.release
, NBBY
* (uint_t
)sizeof (void *));
253 printf("DEBUG enabled\n");
258 * Allocate a log device corresponding to supplied device type.
259 * Both devices are clonable. /dev/log devices are allocated per zone.
260 * /dev/conslog devices are allocated from kmem cache.
263 log_alloc(minor_t type
)
265 zone_t
*zptr
= curproc
->p_zone
;
271 if (type
== LOG_CONSMIN
) {
274 * Return a write-only /dev/conslog device.
275 * No point allocating log_t until there's a free minor number.
277 minor
= (minor_t
)id_alloc(log_minorspace
);
278 lp
= kmem_cache_alloc(log_cons_cache
, KM_SLEEP
);
279 lp
->log_minor
= minor
;
282 ASSERT(type
== LOG_LOGMIN
);
284 lzp
= zone_getspecific(log_zone_key
, zptr
);
287 /* search for an available /dev/log device for the zone */
288 for (i
= LOG_LOGMINIDX
; i
<= LOG_LOGMAXIDX
; i
++) {
289 lp
= &lzp
->lz_clones
[i
];
290 if (lp
->log_inuse
== 0)
293 if (i
> LOG_LOGMAXIDX
)
296 /* Indicate which device type */
297 lp
->log_major
= LOG_LOGMIN
;
305 id_free(log_minorspace
, lp
->log_minor
);
306 kmem_cache_free(log_cons_cache
, lp
);
310 * Move console messages from src to dst. The time of day isn't known
311 * early in boot, so fix up the message timestamps if necessary.
314 log_conswitch(log_t
*src
, log_t
*dst
)
321 while ((mp
= getq_noenab(src
->log_q
, 0)) != NULL
) {
322 log_ctl_t
*lc
= (log_ctl_t
*)mp
->b_rptr
;
323 lc
->flags
|= SL_LOGONLY
;
326 * The ttime is written with 0 in log_sensmsg() only when
327 * good gethrestime_sec() data is not available to store in
328 * the log_ctl_t in the early boot phase.
330 if (lc
->ttime
== 0) {
332 * Look ahead to first early boot message with time.
345 hlc
= (log_ctl_t
*)hmp
->b_rptr
;
347 * Calculate hrestime for an early log message with
348 * an invalid time stamp. We know:
349 * - the lbolt of the invalid time stamp.
350 * - the hrestime and lbolt of the first valid
353 hlc
->ttime
= lc
->ttime
- (lc
->ltime
- hlc
->ltime
) / hz
;
354 (void) putq(dst
->log_q
, hmp
);
357 (void) putq(dst
->log_q
, mp
);
362 hlc
= (log_ctl_t
*)hmp
->b_rptr
;
363 hlc
->ttime
= gethrestime_sec() -
364 (ddi_get_lbolt() - hlc
->ltime
) / hz
;
365 (void) putq(dst
->log_q
, hmp
);
368 dst
->log_overflow
= src
->log_overflow
;
370 dst
->log_flags
= SL_CONSOLE
;
371 log_consq
= dst
->log_q
;
375 * Set the fields in the 'target' clone to the specified values.
376 * Then, look at all clones to determine which message types are
377 * currently active and which clone is the primary console queue.
378 * If the primary console queue changes to or from the backlog
379 * queue, copy all messages from backlog to primary or vice versa.
382 log_update(log_t
*target
, queue_t
*q
, short flags
, log_filter_t
*filter
)
385 short active
= SL_CONSOLE
;
388 zoneid_t zoneid
= target
->log_zoneid
;
395 target
->log_wanted
= filter
;
396 target
->log_flags
= flags
;
397 target
->log_overflow
= 0;
400 * Need to special case the global zone here since this may be
401 * called before zone_init.
403 if (zoneid
== GLOBAL_ZONEID
) {
405 } else if ((zptr
= zone_find_by_id(zoneid
)) == NULL
) {
407 return; /* zone is being destroyed, ignore update */
409 lzp
= zone_getspecific(log_zone_key
, zptr
);
412 for (i
= LOG_LOGMAXIDX
; i
>= LOG_LOGMINIDX
; i
--) {
413 lp
= &lzp
->lz_clones
[i
];
414 if (zoneid
== GLOBAL_ZONEID
&& (lp
->log_flags
& SL_CONSOLE
))
415 log_consq
= lp
->log_q
;
416 active
|= lp
->log_flags
;
418 lzp
->lz_active
= active
;
423 if (log_consq
== target
->log_q
) {
424 if (flags
& SL_CONSOLE
)
425 log_conswitch(&log_backlog
, target
);
427 log_conswitch(target
, &log_backlog
);
436 log_error(log_t
*lp
, log_ctl_t
*lc
)
438 if ((lc
->pri
& LOG_FACMASK
) == LOG_KERN
)
439 lc
->pri
= LOG_KERN
| LOG_ERR
;
444 log_trace(log_t
*lp
, log_ctl_t
*lc
)
446 trace_ids_t
*tid
= (trace_ids_t
*)lp
->log_data
->b_rptr
;
447 trace_ids_t
*tidend
= (trace_ids_t
*)lp
->log_data
->b_wptr
;
450 * We use `tid + 1 <= tidend' here rather than the more traditional
451 * `tid < tidend', since the former ensures that there's at least
452 * `sizeof (trace_ids_t)' bytes available before executing the
453 * loop, whereas the latter only ensures that there's a single byte.
455 for (; tid
+ 1 <= tidend
; tid
++) {
456 if (tid
->ti_level
< lc
->level
&& tid
->ti_level
>= 0)
458 if (tid
->ti_mid
!= lc
->mid
&& tid
->ti_mid
>= 0)
460 if (tid
->ti_sid
!= lc
->sid
&& tid
->ti_sid
>= 0)
462 if ((lc
->pri
& LOG_FACMASK
) == LOG_KERN
)
463 lc
->pri
= LOG_KERN
| LOG_DEBUG
;
471 log_console(log_t
*lp
, log_ctl_t
*lc
)
473 if ((lc
->pri
& LOG_FACMASK
) == LOG_KERN
) {
474 if (lc
->flags
& SL_FATAL
)
475 lc
->pri
= LOG_KERN
| LOG_CRIT
;
476 else if (lc
->flags
& SL_ERROR
)
477 lc
->pri
= LOG_KERN
| LOG_ERR
;
478 else if (lc
->flags
& SL_WARN
)
479 lc
->pri
= LOG_KERN
| LOG_WARNING
;
480 else if (lc
->flags
& SL_NOTE
)
481 lc
->pri
= LOG_KERN
| LOG_NOTICE
;
482 else if (lc
->flags
& SL_TRACE
)
483 lc
->pri
= LOG_KERN
| LOG_DEBUG
;
485 lc
->pri
= LOG_KERN
| LOG_INFO
;
491 log_makemsg(int mid
, int sid
, int level
, int sl
, int pri
, void *msg
,
492 size_t size
, int on_intr
)
498 if (size
<= LOG_MSGSIZE
&&
499 (on_intr
|| log_freeq
->q_count
> log_freeq
->q_lowat
))
500 mp
= getq_noenab(log_freeq
, 0);
504 (mp
= allocb(sizeof (log_ctl_t
), BPRI_HI
)) == NULL
||
505 (mp2
= allocb(MAX(size
, LOG_MSGSIZE
), BPRI_HI
)) == NULL
) {
509 DB_TYPE(mp
) = M_PROTO
;
510 mp
->b_wptr
+= sizeof (log_ctl_t
);
514 mp2
->b_wptr
= mp2
->b_rptr
;
517 lc
= (log_ctl_t
*)mp
->b_rptr
;
524 bcopy(msg
, mp2
->b_wptr
, size
- 1);
525 mp2
->b_wptr
[size
- 1] = '\0';
526 mp2
->b_wptr
+= strlen((char *)mp2
->b_wptr
) + 1;
532 log_freemsg(mblk_t
*mp
)
534 mblk_t
*mp2
= mp
->b_cont
;
536 ASSERT(MBLKL(mp
) == sizeof (log_ctl_t
));
537 ASSERT(mp2
->b_rptr
== mp2
->b_datap
->db_base
);
539 if ((log_freeq
->q_flag
& QFULL
) == 0 &&
540 MBLKL(mp2
) <= LOG_MSGSIZE
&& MBLKSIZE(mp2
) >= LOG_MSGSIZE
)
541 (void) putq(log_freeq
, mp
);
547 log_sendmsg(mblk_t
*mp
, zoneid_t zoneid
)
551 mblk_t
*mp2
= mp
->b_cont
;
552 log_ctl_t
*lc
= (log_ctl_t
*)mp
->b_rptr
;
562 * Need to special case the global zone here since this may be
563 * called before zone_init.
565 if (zoneid
== GLOBAL_ZONEID
) {
567 } else if ((zptr
= zone_find_by_id(zoneid
)) == NULL
) {
568 /* specified zone doesn't exist, free message and return */
572 lzp
= zone_getspecific(log_zone_key
, zptr
);
576 if ((lc
->flags
& lzp
->lz_active
) == 0) {
585 * Raise the console queue's q_hiwat to ensure that we
586 * capture all panic messages.
588 log_consq
->q_hiwat
= 2 * LOG_HIWAT
;
589 log_consq
->q_flag
&= ~QFULL
;
591 /* Message was created while panicking. */
592 lc
->flags
|= SL_PANICMSG
;
595 src
= (char *)mp2
->b_rptr
;
596 dst
= strstr(src
, "FACILITY_AND_PRIORITY] ");
598 facility
= dst
- src
;
599 body
= facility
+ 23; /* strlen("FACILITY_AND_PRIORITY] ") */
605 * In the early boot phase hrestime is invalid, then timechanged is 0.
606 * If hrestime is not valid, the ttime is set to 0 here and the correct
607 * ttime is calculated in log_conswitch() later. The log_conswitch()
608 * calculation to determine the correct ttime does not use ttime data
609 * from these log_ctl_t structures; it only uses ttime from log_ctl_t's
610 * that contain good data.
613 lc
->ltime
= ddi_get_lbolt();
615 lc
->ttime
= gethrestime_sec();
620 flags
= lc
->flags
& lzp
->lz_active
;
621 log_seq_no
[flags
& SL_ERROR
]++;
622 log_seq_no
[flags
& SL_TRACE
]++;
623 log_seq_no
[flags
& SL_CONSOLE
]++;
626 * If this is in the global zone, start with the backlog, then
627 * walk through the clone logs. If not, just do the clone logs.
629 backlog
= (zoneid
== GLOBAL_ZONEID
);
631 while (i
<= LOG_LOGMAXIDX
) {
634 * Do the backlog this time, then start on the
640 lp
= &lzp
->lz_clones
[i
++];
643 if ((lp
->log_flags
& flags
) && lp
->log_wanted(lp
, lc
)) {
644 if (canput(lp
->log_q
)) {
645 lp
->log_overflow
= 0;
646 lc
->seq_no
= log_seq_no
[lp
->log_flags
];
647 if ((mp2
= copymsg(mp
)) == NULL
)
650 src
= (char *)mp2
->b_cont
->b_rptr
;
651 dst
= src
+ facility
;
652 fac
= (lc
->pri
& LOG_FACMASK
) >> 3;
654 LOG_FACSIZE
+ LOG_PRISIZE
, "%s.%s",
655 log_fac
[MIN(fac
, LOG_NFACILITIES
)],
656 log_pri
[lc
->pri
& LOG_PRIMASK
]);
657 src
+= body
- 2; /* copy "] " too */
661 mp2
->b_cont
->b_wptr
= (uchar_t
*)dst
;
663 (void) putq(lp
->log_q
, mp2
);
664 } else if (++lp
->log_overflow
== 1) {
665 if (lp
->log_q
== log_consq
) {
666 console_printf(log_overflow_msg
,
668 " -- is syslogd(1M) running?");
670 printf(log_overflow_msg
,
680 if ((flags
& SL_CONSOLE
) && (lc
->pri
& LOG_FACMASK
) == LOG_KERN
) {
681 if ((mp2
== NULL
|| log_consq
== log_backlogq
|| panicstr
) &&
682 (lc
->flags
& SL_LOGONLY
) == 0)
683 console_printf("%s", (char *)mp
->b_cont
->b_rptr
+ body
);
684 if ((lc
->flags
& SL_CONSONLY
) == 0 &&
685 (mp2
= copymsg(mp
)) != NULL
) {
686 mp2
->b_cont
->b_rptr
+= body
;
687 if (log_recentq
->q_flag
& QFULL
)
688 freemsg(getq_noenab(log_recentq
, 0));
689 (void) putq(log_recentq
, mp2
);
699 * Print queued messages to console.
702 log_printq(queue_t
*qfirst
)
710 * Look ahead to first queued message in the stream.
714 for (q
= qfirst
; q
->q_next
!= qlast
; q
= q
->q_next
)
716 for (mp
= q
->q_first
; mp
!= NULL
; mp
= mp
->b_next
) {
717 lc
= (log_ctl_t
*)mp
->b_rptr
;
719 * Check if message is already displayed at
722 if (lc
->flags
& SL_PANICMSG
)
725 cp
= (char *)mp
->b_cont
->b_rptr
;
727 /* Strip off the message ID. */
728 if ((msgp
= strstr(cp
, "[ID ")) != NULL
&&
729 (msgp
= strstr(msgp
, "] ")) != NULL
) {
734 * Using console_printf instead of printf to avoid
735 * queueing messages to log_consq.
737 console_printf("%s", cp
);
739 } while ((qlast
= q
) != qfirst
);
744 log_cons_constructor(void *buf
, void *cdrarg
, int kmflags
)
746 struct log
*lp
= buf
;
748 lp
->log_zoneid
= GLOBAL_ZONEID
;
749 lp
->log_major
= LOG_CONSMIN
; /* Indicate which device type */
756 log_cons_destructor(void *buf
, void *cdrarg
)
758 struct log
*lp
= buf
;
760 ASSERT(lp
->log_zoneid
== GLOBAL_ZONEID
);
761 ASSERT(lp
->log_major
== LOG_CONSMIN
);
762 ASSERT(lp
->log_data
== NULL
);