LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
From: Yinghai Lu <yhlu.kernel@gmail.com>
To: Ingo Molnar <mingo@elte.hu>, Thomas Gleixner <tglx@linutronix.de>,
	"H. Peter Anvin" <hpa@zytor.com>,
	Andrew Morton <akpm@linux-foundation.org>
Cc: linux-kernel@vger.kernel.org, Yinghai Lu <yhlu.kernel@gmail.com>
Subject: [PATCH 1/7] add DEFINE_LOGLEVEL_SETUP
Date: Wed, 17 Sep 2008 17:18:25 -0700	[thread overview]
Message-ID: <1221697112-21814-2-git-send-email-yhlu.kernel@gmail.com> (raw)
In-Reply-To: <1221697112-21814-1-git-send-email-yhlu.kernel@gmail.com>

so could make subsys easy to add loglevel and xxx_printk
v2: make it more genric, so subsys user only need to two line macro
v3: add back nameStr, so could find out iommu: and iommu_gart: and etc
v4: use printk intead of pci_printk
v5: fix checkpatch error and warning
v6: add DEFINE_LOGLEVEL_SETUP_DEF to take default
v7: call tag_loglevel_setup only one time, so could take several loglevel like
   loglevel=4 loglevel=acpi:8 loglevel=pci:8 loglevel=apic:8 is the same as
   loglevel=4,acpi:8,pci:8,apic:8
v8: add _SPEW, _EXTRA
    expand msg_level to 2 digi bits
    call tag_name_level_setup second time if user change console_loglevel
    add get_tag_level, so could use it to find out current level of spcified tag

usage:
	in .h to have
		#define KERN_PCI "<pci>"
	in .c to have
		DEFINE_LOGLEVEL_SETUP(pci, KERN_PCI, "pci:");
	then could use
		printk(KERN_DEBUG KERN_PCI fmt, ...);
	and command line
		loglevel=pci:8

you can add different printk to different files of one subsys if you like

Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com>
---
 arch/x86/kernel/vmlinux_32.lds.S  |    1 
 arch/x86/kernel/vmlinux_64.lds.S  |    2 
 include/asm-generic/vmlinux.lds.h |    8 +
 include/linux/init.h              |   22 +++++
 include/linux/kernel.h            |    4 
 init/main.c                       |  156 ++++++++++++++++++++++++++++++++++++--
 kernel/printk.c                   |   90 ++++++++++++++++++---
 7 files changed, 259 insertions(+), 24 deletions(-)

Index: linux-2.6/arch/x86/kernel/vmlinux_32.lds.S
===================================================================
--- linux-2.6.orig/arch/x86/kernel/vmlinux_32.lds.S
+++ linux-2.6/arch/x86/kernel/vmlinux_32.lds.S
@@ -145,6 +145,7 @@ SECTIONS
 	*(.x86_cpu_dev.init)
 	__x86_cpu_dev_end = .;
   }
+  LOGLEVEL_SETUP_INIT(8)
   DYN_ARRAY_INIT(8)
   SECURITY_INIT
   . = ALIGN(4);
Index: linux-2.6/arch/x86/kernel/vmlinux_64.lds.S
===================================================================
--- linux-2.6.orig/arch/x86/kernel/vmlinux_64.lds.S
+++ linux-2.6/arch/x86/kernel/vmlinux_64.lds.S
@@ -174,6 +174,8 @@ SECTIONS
   }
   __x86_cpu_dev_end = .;
 
+  LOGLEVEL_SETUP_INIT(8)
+
   DYN_ARRAY_INIT(8)
 
   SECURITY_INIT
Index: linux-2.6/include/asm-generic/vmlinux.lds.h
===================================================================
--- linux-2.6.orig/include/asm-generic/vmlinux.lds.h
+++ linux-2.6/include/asm-generic/vmlinux.lds.h
@@ -222,6 +222,14 @@
  * All archs are supposed to use RO_DATA() */
 #define RODATA RO_DATA(4096)
 
+#define LOGLEVEL_SETUP_INIT(align)					\
+	. = ALIGN((align));						\
+	.loglevel_setup.init : AT(ADDR(.loglevel_setup.init) - LOAD_OFFSET) { \
+		VMLINUX_SYMBOL(__loglevel_setup_start) = .;		\
+		*(.loglevel_setup.init)					\
+		VMLINUX_SYMBOL(__loglevel_setup_end) = .;		\
+	}
+
 #define DYN_ARRAY_INIT(align)							\
 	. = ALIGN((align));						\
 	.dyn_array.init : AT(ADDR(.dyn_array.init) - LOAD_OFFSET) {	\
Index: linux-2.6/include/linux/init.h
===================================================================
--- linux-2.6.orig/include/linux/init.h
+++ linux-2.6/include/linux/init.h
@@ -251,6 +251,28 @@ struct obs_kernel_param {
 /* Relies on boot_command_line being set */
 void __init parse_early_param(void);
 
+struct loglevel_setup {
+	char *name;
+	char *tag;
+	int level;
+};
+
+extern struct loglevel_setup *__loglevel_setup_start[], *__loglevel_setup_end[];
+
+#define DEFINE_LOGLEVEL_SETUP_DEF(nameX, tagX, nameStr, levelX)		\
+	static struct loglevel_setup __loglevel_setup_##nameX __initdata = \
+	{							\
+		.tag = tagX,					\
+		.name = nameStr,				\
+		.level = levelX,				\
+	};							\
+	static struct loglevel_setup *__loglevel_setup_ptr_##nameX __used \
+	__attribute__((__section__(".loglevel_setup.init"))) =	\
+		&__loglevel_setup_##nameX
+
+#define DEFINE_LOGLEVEL_SETUP(nameX, tagX, nameStr)		\
+	DEFINE_LOGLEVEL_SETUP_DEF(nameX, tagX, nameStr, 0)
+
 struct dyn_array {
 	void **name;
 	unsigned long size;
Index: linux-2.6/include/linux/kernel.h
===================================================================
--- linux-2.6.orig/include/linux/kernel.h
+++ linux-2.6/include/linux/kernel.h
@@ -89,6 +89,8 @@ extern const char linux_proc_banner[];
 #define	KERN_NOTICE	"<5>"	/* normal but significant condition	*/
 #define	KERN_INFO	"<6>"	/* informational			*/
 #define	KERN_DEBUG	"<7>"	/* debug-level messages			*/
+#define	KERN_SPEW	"<8>"	/* spew messages			*/
+#define	KERN_EXTRA	"<9>"	/* extra messages			*/
 
 /*
  * Annotation for a "continued" line of log printout (only done after a
@@ -104,6 +106,8 @@ extern int console_printk[];
 #define minimum_console_loglevel (console_printk[2])
 #define default_console_loglevel (console_printk[3])
 
+extern int get_tag_level(char *str, int *slen);
+
 struct completion;
 struct pt_regs;
 struct user;
Index: linux-2.6/init/main.c
===================================================================
--- linux-2.6.orig/init/main.c
+++ linux-2.6/init/main.c
@@ -233,29 +233,168 @@ unsigned long loops_per_jiffy = (1<<12);
 
 EXPORT_SYMBOL(loops_per_jiffy);
 
-static int __init debug_kernel(char *str)
-{
-	console_loglevel = 10;
+struct tag_console_loglevel {
+	char tag[32];
+	char name[32];
+	int level;
+};
+
+#define CONSOLE_TAG_LEVEL_NR	32
+static struct tag_console_loglevel tag_level[CONSOLE_TAG_LEVEL_NR];
+static int tag_level_nr;
+
+static int __init add_tag_name_level(const char *tag, const char *name,
+					int level)
+{
+	int len;
+
+	if (tag_level_nr > CONSOLE_TAG_LEVEL_NR)
+		return -1;
+
+	len = sizeof(tag_level[tag_level_nr].tag);
+	strncpy(tag_level[tag_level_nr].tag, tag, len - 1);
+	len = sizeof(tag_level[tag_level_nr].name);
+	strncpy(tag_level[tag_level_nr].name, name, len - 1);
+	tag_level[tag_level_nr].level = level;
+
+	tag_level_nr++;
+
 	return 0;
 }
 
-static int __init quiet_kernel(char *str)
+static int __init update_tag_name_level(const char *tag, const char *name,
+					int level)
 {
-	console_loglevel = 4;
+	int i;
+	int len;
+
+	for (i = 0; i < tag_level_nr; i++) {
+		len = strlen(tag_level[i].tag);
+		if (strncmp(tag_level[i].tag, tag, len))
+			continue;
+		if (name) {
+			len = sizeof(tag_level[i].name);
+			strncpy(tag_level[i].name, name, len - 1);
+		}
+		tag_level[i].level = level;
+
+		return 1;
+	}
+
 	return 0;
 }
 
-early_param("debug", debug_kernel);
-early_param("quiet", quiet_kernel);
+static int __init save_tag_name_level(const char *tag, const char *name,
+					int level)
+{
+	int ret;
+
+	ret = update_tag_name_level(tag, name, level);
+
+	/* not found, add a new one */
+	if (!ret)
+		ret = add_tag_name_level(tag, name, level);
+
+	return ret;
+}
+
+int get_tag_level(char *str, int *slen)
+{
+	int i;
+	int level = 0;
+
+	/* handle tag here */
+	for (i = 0; i < tag_level_nr; i++) {
+		struct tag_console_loglevel *tl;
+		int len;
+
+		tl = &tag_level[i];
+		len = strlen(tl->tag);
+		if (*slen > (len - 1) && !strncmp(str, tl->tag, len)) {
+			level = tl->level;
+			*slen = len;
+			break;
+		}
+	}
+
+	return level;
+}
+
+static void __init tag_loglevel_setup(void)
+{
+	struct loglevel_setup **la;
+	int level = console_loglevel;
+
+	for (la = __loglevel_setup_start ; la < __loglevel_setup_end; la++) {
+		struct loglevel_setup *l = *la;
+
+		save_tag_name_level(l->tag, l->name, l->level ? : level);
+	}
+}
+
+static char __init *real_loglevel_setup(char *str)
+{
+	int i;
+
+	for (i = 0; i < tag_level_nr; i++) {
+		struct tag_console_loglevel *tl;
+		int len;
+
+		tl = &tag_level[i];
+		len = strlen(tl->name);
+		if (!strncmp(str, tl->name, len)) {
+			int level;
+
+			str += len;
+			get_option(&str, &level);
+			tl->level = level;
+			str = NULL;
+			break;
+		}
+	}
+
+	return str;
+}
 
 static int __init loglevel(char *str)
 {
-	get_option(&str, &console_loglevel);
+	while (str) {
+		char *k = strchr(str, ',');
+
+		if (k)
+			*k++ = 0;
+		if (*str) {
+			str = real_loglevel_setup(str);
+			if (str && *str) {
+				get_option(&str, &console_loglevel);
+				tag_loglevel_setup();
+			}
+		}
+		str = k;
+	}
+
 	return 0;
 }
 
 early_param("loglevel", loglevel);
 
+static int __init debug_kernel(char *str)
+{
+	console_loglevel = 10;
+	tag_loglevel_setup();
+	return 0;
+}
+
+static int __init quiet_kernel(char *str)
+{
+	console_loglevel = 4;
+	tag_loglevel_setup();
+	return 0;
+}
+
+early_param("debug", debug_kernel);
+early_param("quiet", quiet_kernel);
+
 /*
  * Unknown boot options get handed to init, unless they look like
  * failed parameters
@@ -581,6 +720,7 @@ asmlinkage void __init start_kernel(void
 	page_address_init();
 	printk(KERN_NOTICE);
 	printk(linux_banner);
+	tag_loglevel_setup();
 	setup_arch(&command_line);
 	pre_alloc_dyn_array();
 	mm_init_owner(&init_mm, &init_task);
Index: linux-2.6/kernel/printk.c
===================================================================
--- linux-2.6.orig/kernel/printk.c
+++ linux-2.6/kernel/printk.c
@@ -457,9 +457,9 @@ early_param("ignore_loglevel", ignore_lo
  * Write out chars from start to end - 1 inclusive
  */
 static void _call_console_drivers(unsigned start,
-				unsigned end, int msg_log_level)
+				unsigned end, int msg_log_level, int level)
 {
-	if ((msg_log_level < console_loglevel || ignore_loglevel) &&
+	if ((msg_log_level < level || ignore_loglevel) &&
 			console_drivers && start != end) {
 		if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) {
 			/* wrapped write */
@@ -481,21 +481,55 @@ static void call_console_drivers(unsigne
 {
 	unsigned cur_index, start_print;
 	static int msg_level = -1;
+	int level = console_loglevel;
 
 	BUG_ON(((int)(start - end)) > 0);
 
 	cur_index = start;
 	start_print = start;
 	while (cur_index != end) {
-		if (msg_level < 0 && ((end - cur_index) > 2) &&
-				LOG_BUF(cur_index + 0) == '<' &&
-				LOG_BUF(cur_index + 1) >= '0' &&
-				LOG_BUF(cur_index + 1) <= '7' &&
-				LOG_BUF(cur_index + 2) == '>') {
-			msg_level = LOG_BUF(cur_index + 1) - '0';
-			cur_index += 3;
+		int tag_level;
+		int tag_len;
+
+		if (msg_level < 0) {
+			int len = 0;
+
+			if (((end - cur_index) > 2) &&
+					LOG_BUF(cur_index + 0) == '<' &&
+					LOG_BUF(cur_index + 1) >= '0' &&
+					LOG_BUF(cur_index + 1) <= '9' &&
+					LOG_BUF(cur_index + 2) == '>') {
+				msg_level = LOG_BUF(cur_index + 1) - '0';
+				len = 3;
+			} else if (((end - cur_index) > 3) &&
+					LOG_BUF(cur_index + 0) == '<' &&
+					LOG_BUF(cur_index + 1) >= '0' &&
+					LOG_BUF(cur_index + 1) <= '9' &&
+					LOG_BUF(cur_index + 2) >= '0' &&
+					LOG_BUF(cur_index + 2) <= '9' &&
+					LOG_BUF(cur_index + 3) == '>') {
+				msg_level = LOG_BUF(cur_index + 1) - '0';
+				msg_level *= 10;
+				msg_level += LOG_BUF(cur_index + 2) - '0';
+				len = 4;
+			}
+
+			if (len) {
+				level = console_loglevel;
+				cur_index += len;
+				start_print = cur_index;
+			}
+		}
+
+		/* handle tag here */
+		tag_len = end - cur_index;
+		tag_level = get_tag_level(&LOG_BUF(cur_index), &tag_len);
+		if (tag_level) {
+			level = tag_level;
+			cur_index += tag_len;
 			start_print = cur_index;
 		}
+
 		while (cur_index != end) {
 			char c = LOG_BUF(cur_index);
 
@@ -510,14 +544,15 @@ static void call_console_drivers(unsigne
 					 */
 					msg_level = default_message_loglevel;
 				}
-				_call_console_drivers(start_print, cur_index, msg_level);
+				_call_console_drivers(start_print, cur_index,
+							msg_level, level);
 				msg_level = -1;
 				start_print = cur_index;
 				break;
 			}
 		}
 	}
-	_call_console_drivers(start_print, end, msg_level);
+	_call_console_drivers(start_print, end, msg_level, level);
 }
 
 static void emit_log_char(char c)
@@ -712,19 +747,42 @@ asmlinkage int vprintk(const char *fmt,
 	 */
 	for (p = printk_buf; *p; p++) {
 		if (new_text_line) {
+			int len = 0;
+
 			/* If a token, set current_log_level and skip over */
-			if (p[0] == '<' && p[1] >= '0' && p[1] <= '7' &&
+			if (p[0] == '<' && p[1] >= '0' && p[1] <= '9' &&
 			    p[2] == '>') {
 				current_log_level = p[1] - '0';
-				p += 3;
-				printed_len -= 3;
+				len = 3;
+			} else if (p[0] == '<' && p[1] >= '0' && p[1] <= '9' &&
+				   p[2] >= '0' && p[2] <= '9' && p[3] == '>') {
+				current_log_level = p[1] - '0';
+				current_log_level *= 10;
+				current_log_level += p[2] - '0';
+				len = 4;
+			}
+
+			if (len) {
+				p += len;
+				printed_len -= len;
 			}
 
 			/* Always output the token */
 			emit_log_char('<');
-			emit_log_char(current_log_level + '0');
+			if (current_log_level < 10) {
+				emit_log_char(current_log_level + '0');
+				len = 3;
+			} else {
+				int temp;
+
+				temp = current_log_level/10;
+				emit_log_char(temp + '0');
+				temp *= 10;
+				emit_log_char(current_log_level - temp + '0');
+				len = 4;
+			}
 			emit_log_char('>');
-			printed_len += 3;
+			printed_len += len;
 			new_text_line = 0;
 
 			if (printk_time) {

  reply	other threads:[~2008-09-18  0:19 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-09-18  0:18 [PATCH 0/7] loglevel=pci:8,acpi:8,apic=12,dev:8 support v7 Yinghai Lu
2008-09-18  0:18 ` Yinghai Lu [this message]
2008-09-18  0:18 ` [PATCH 2/7] pci: add KERN_PCI Yinghai Lu
2008-09-18  0:18 ` [PATCH 3/7] pci: using printk(KERN_PCI v3 Yinghai Lu
2008-09-18  0:18 ` [PATCH 4/7] acpi: add KERN_ACPI v3 Yinghai Lu
2008-09-18  0:18 ` [PATCH 5/7] acpi: dump slit with printk(KERN_ACPI...) Yinghai Lu
2008-09-18  0:18 ` [PATCH 6/7] x86: add KERN_APIC Yinghai Lu
2008-09-18  0:18 ` [PATCH 7/7] pci: add KERN_PCI Yinghai Lu
2008-09-18  0:18 ` [PATCH] pci: using %pF in quirks.c Yinghai Lu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1221697112-21814-2-git-send-email-yhlu.kernel@gmail.com \
    --to=yhlu.kernel@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=hpa@zytor.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@elte.hu \
    --cc=tglx@linutronix.de \
    --subject='Re: [PATCH 1/7] add DEFINE_LOGLEVEL_SETUP' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).