1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright 2023 Red Hat
8 #include <asm/current.h>
9 #include <linux/delay.h>
10 #include <linux/hardirq.h>
11 #include <linux/module.h>
12 #include <linux/printk.h>
13 #include <linux/sched.h>
16 #include "thread-device.h"
17 #include "thread-utils.h"
19 int vdo_log_level
= VDO_LOG_DEFAULT
;
21 int vdo_get_log_level(void)
23 int log_level_latch
= READ_ONCE(vdo_log_level
);
25 if (unlikely(log_level_latch
> VDO_LOG_MAX
)) {
26 log_level_latch
= VDO_LOG_DEFAULT
;
27 WRITE_ONCE(vdo_log_level
, log_level_latch
);
29 return log_level_latch
;
32 static const char *get_current_interrupt_type(void)
47 * emit_log_message_to_kernel() - Emit a log message to the kernel at the specified priority.
49 * @priority: The priority at which to log the message
50 * @fmt: The format string of the message
52 static void emit_log_message_to_kernel(int priority
, const char *fmt
, ...)
57 if (priority
> vdo_get_log_level())
81 pr_debug("%pV", &vaf
);
84 printk(KERN_DEFAULT
"%pV", &vaf
);
92 * emit_log_message() - Emit a log message to the kernel log in a format suited to the current
95 * Context info formats:
97 * interrupt: uds[NMI]: blah
98 * kvdo thread: kvdo12:foobarQ: blah
99 * thread w/device id: kvdo12:myprog: blah
100 * other thread: uds: myprog: blah
102 * Fields: module name, interrupt level, process name, device ID.
104 * @priority: the priority at which to log the message
105 * @module: The name of the module doing the logging
106 * @prefix: The prefix of the log message
107 * @vaf1: The first message format descriptor
108 * @vaf2: The second message format descriptor
110 static void emit_log_message(int priority
, const char *module
, const char *prefix
,
111 const struct va_format
*vaf1
, const struct va_format
*vaf2
)
116 * In interrupt context, identify the interrupt type and module. Ignore the process/thread
117 * since it could be anything.
119 if (in_interrupt()) {
120 const char *type
= get_current_interrupt_type();
122 emit_log_message_to_kernel(priority
, "%s[%s]: %s%pV%pV\n", module
, type
,
127 /* Not at interrupt level; we have a process we can look at, and might have a device ID. */
128 device_instance
= vdo_get_thread_device_id();
129 if (device_instance
>= 0) {
130 emit_log_message_to_kernel(priority
, "%s%u:%s: %s%pV%pV\n", module
,
131 device_instance
, current
->comm
, prefix
, vaf1
,
137 * If it's a kernel thread and the module name is a prefix of its name, assume it is ours
138 * and only identify the thread.
140 if (((current
->flags
& PF_KTHREAD
) != 0) &&
141 (strncmp(module
, current
->comm
, strlen(module
)) == 0)) {
142 emit_log_message_to_kernel(priority
, "%s: %s%pV%pV\n", current
->comm
,
147 /* Identify the module and the process. */
148 emit_log_message_to_kernel(priority
, "%s: %s: %s%pV%pV\n", module
, current
->comm
,
153 * vdo_log_embedded_message() - Log a message embedded within another message.
154 * @priority: the priority at which to log the message
155 * @module: the name of the module doing the logging
156 * @prefix: optional string prefix to message, may be NULL
157 * @fmt1: format of message first part (required)
158 * @args1: arguments for message first part (required)
159 * @fmt2: format of message second part
161 void vdo_log_embedded_message(int priority
, const char *module
, const char *prefix
,
162 const char *fmt1
, va_list args1
, const char *fmt2
, ...)
166 struct va_format vaf1
, vaf2
;
168 va_start(args2
, fmt2
);
171 module
= VDO_LOGGING_MODULE_NAME
;
177 * It is implementation dependent whether va_list is defined as an array type that decays
178 * to a pointer when passed as an argument. Copy args1 and args2 with va_copy so that vaf1
179 * and vaf2 get proper va_list pointers irrespective of how va_list is defined.
181 va_copy(args1_copy
, args1
);
183 vaf1
.va
= &args1_copy
;
188 emit_log_message(priority
, module
, prefix
, &vaf1
, &vaf2
);
194 int vdo_vlog_strerror(int priority
, int errnum
, const char *module
, const char *format
,
197 char errbuf
[VDO_MAX_ERROR_MESSAGE_SIZE
];
198 const char *message
= uds_string_error(errnum
, errbuf
, sizeof(errbuf
));
200 vdo_log_embedded_message(priority
, module
, NULL
, format
, args
, ": %s (%d)",
205 int __vdo_log_strerror(int priority
, int errnum
, const char *module
, const char *format
, ...)
209 va_start(args
, format
);
210 vdo_vlog_strerror(priority
, errnum
, module
, format
, args
);
215 void vdo_log_backtrace(int priority
)
217 if (priority
> vdo_get_log_level())
223 void __vdo_log_message(int priority
, const char *module
, const char *format
, ...)
227 va_start(args
, format
);
228 vdo_log_embedded_message(priority
, module
, NULL
, format
, args
, "%s", "");
233 * Sleep or delay a few milliseconds in an attempt to allow the log buffers to be flushed lest they
236 void vdo_pause_for_logger(void)