brintos

brintos / linux-shallow public Read only

0
0
Text · 5.8 KiB · 3f7dc2c Raw
240 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright 2023 Red Hat4 */5 6#include "logger.h"7 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>14 15#include "errors.h"16#include "thread-device.h"17#include "thread-utils.h"18 19int vdo_log_level = VDO_LOG_DEFAULT;20 21int vdo_get_log_level(void)22{23	int log_level_latch = READ_ONCE(vdo_log_level);24 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);28	}29	return log_level_latch;30}31 32static const char *get_current_interrupt_type(void)33{34	if (in_nmi())35		return "NMI";36 37	if (in_irq())38		return "HI";39 40	if (in_softirq())41		return "SI";42 43	return "INTR";44}45 46/**47 * emit_log_message_to_kernel() - Emit a log message to the kernel at the specified priority.48 *49 * @priority: The priority at which to log the message50 * @fmt: The format string of the message51 */52static void emit_log_message_to_kernel(int priority, const char *fmt, ...)53{54	va_list args;55	struct va_format vaf;56 57	if (priority > vdo_get_log_level())58		return;59 60	va_start(args, fmt);61	vaf.fmt = fmt;62	vaf.va = &args;63 64	switch (priority) {65	case VDO_LOG_EMERG:66	case VDO_LOG_ALERT:67	case VDO_LOG_CRIT:68		pr_crit("%pV", &vaf);69		break;70	case VDO_LOG_ERR:71		pr_err("%pV", &vaf);72		break;73	case VDO_LOG_WARNING:74		pr_warn("%pV", &vaf);75		break;76	case VDO_LOG_NOTICE:77	case VDO_LOG_INFO:78		pr_info("%pV", &vaf);79		break;80	case VDO_LOG_DEBUG:81		pr_debug("%pV", &vaf);82		break;83	default:84		printk(KERN_DEFAULT "%pV", &vaf);85		break;86	}87 88	va_end(args);89}90 91/**92 * emit_log_message() - Emit a log message to the kernel log in a format suited to the current93 *                      thread context.94 *95 * Context info formats:96 *97 * interrupt:           uds[NMI]: blah98 * kvdo thread:         kvdo12:foobarQ: blah99 * thread w/device id:  kvdo12:myprog: blah100 * other thread:        uds: myprog: blah101 *102 * Fields: module name, interrupt level, process name, device ID.103 *104 * @priority: the priority at which to log the message105 * @module: The name of the module doing the logging106 * @prefix: The prefix of the log message107 * @vaf1: The first message format descriptor108 * @vaf2: The second message format descriptor109 */110static void emit_log_message(int priority, const char *module, const char *prefix,111			     const struct va_format *vaf1, const struct va_format *vaf2)112{113	int device_instance;114 115	/*116	 * In interrupt context, identify the interrupt type and module. Ignore the process/thread117	 * since it could be anything.118	 */119	if (in_interrupt()) {120		const char *type = get_current_interrupt_type();121 122		emit_log_message_to_kernel(priority, "%s[%s]: %s%pV%pV\n", module, type,123					   prefix, vaf1, vaf2);124		return;125	}126 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,132					   vaf2);133		return;134	}135 136	/*137	 * If it's a kernel thread and the module name is a prefix of its name, assume it is ours138	 * and only identify the thread.139	 */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,143					   prefix, vaf1, vaf2);144		return;145	}146 147	/* Identify the module and the process. */148	emit_log_message_to_kernel(priority, "%s: %s: %s%pV%pV\n", module, current->comm,149				   prefix, vaf1, vaf2);150}151 152/*153 * vdo_log_embedded_message() - Log a message embedded within another message.154 * @priority: the priority at which to log the message155 * @module: the name of the module doing the logging156 * @prefix: optional string prefix to message, may be NULL157 * @fmt1: format of message first part (required)158 * @args1: arguments for message first part (required)159 * @fmt2: format of message second part160 */161void vdo_log_embedded_message(int priority, const char *module, const char *prefix,162			      const char *fmt1, va_list args1, const char *fmt2, ...)163{164	va_list args1_copy;165	va_list args2;166	struct va_format vaf1, vaf2;167 168	va_start(args2, fmt2);169 170	if (module == NULL)171		module = VDO_LOGGING_MODULE_NAME;172 173	if (prefix == NULL)174		prefix = "";175 176	/*177	 * It is implementation dependent whether va_list is defined as an array type that decays178	 * to a pointer when passed as an argument. Copy args1 and args2 with va_copy so that vaf1179	 * and vaf2 get proper va_list pointers irrespective of how va_list is defined.180	 */181	va_copy(args1_copy, args1);182	vaf1.fmt = fmt1;183	vaf1.va = &args1_copy;184 185	vaf2.fmt = fmt2;186	vaf2.va = &args2;187 188	emit_log_message(priority, module, prefix, &vaf1, &vaf2);189 190	va_end(args1_copy);191	va_end(args2);192}193 194int vdo_vlog_strerror(int priority, int errnum, const char *module, const char *format,195		      va_list args)196{197	char errbuf[VDO_MAX_ERROR_MESSAGE_SIZE];198	const char *message = uds_string_error(errnum, errbuf, sizeof(errbuf));199 200	vdo_log_embedded_message(priority, module, NULL, format, args, ": %s (%d)",201				 message, errnum);202	return errnum;203}204 205int __vdo_log_strerror(int priority, int errnum, const char *module, const char *format, ...)206{207	va_list args;208 209	va_start(args, format);210	vdo_vlog_strerror(priority, errnum, module, format, args);211	va_end(args);212	return errnum;213}214 215void vdo_log_backtrace(int priority)216{217	if (priority > vdo_get_log_level())218		return;219 220	dump_stack();221}222 223void __vdo_log_message(int priority, const char *module, const char *format, ...)224{225	va_list args;226 227	va_start(args, format);228	vdo_log_embedded_message(priority, module, NULL, format, args, "%s", "");229	va_end(args);230}231 232/*233 * Sleep or delay a few milliseconds in an attempt to allow the log buffers to be flushed lest they234 * be overrun.235 */236void vdo_pause_for_logger(void)237{238	fsleep(4000);239}240