* Untested patch 1/2 - add ugly printk macros to kernel (was Re: [RFC] CONFIG_TINY)
2002-10-24 3:01 ` Elladan
@ 2002-10-25 5:19 ` Elladan
2002-10-25 5:20 ` Untested patch 2/2 - Fix some kernel sources for macro printk " Elladan
1 sibling, 0 replies; 10+ messages in thread
From: Elladan @ 2002-10-25 5:19 UTC (permalink / raw)
To: Rasmus Andersen; +Cc: linux-kernel
Here is an untested patch example against 2.5.44 to add some ugly printk
macros to the kernel, to reduce kernel image size for tiny systems.
I verified that this builds a kernel image on my system (if I fix some
2.5.44 build failures, obviously), with the fixup patch I'm sending next
to modify some of the sources for the new printk style.
This patch is hardly complete, and is just an example of using macros to
selectively cut out printk string/code bloat from the kernel. By
changing the TAG_PRINTK_LVL and UNTAG_PRINTK_LVL numbers, selective
levels of printks can be compiled out of the kernel.
With my config and gcc-3.1 (which has dead-string pruning), I got these
build-size numbers with different TAG_PRINTK values:
Define printk like normal (#define printk(a,arg...) _printk(a, ##arg))
System is 1093 kB
All levels on (7 TAG/7 UNTAG)
System is 1090 kB (3k less, not sure why)
Only tagged warning or above (4/7)
System is 1024 kB
Only tagged alert or above (1/7)
System is 1002 kB
Only tagged emergency (0/7)
System is 1002 kB
All printk off (-1/7)
System is 997 kB
Kill printk completely (#define printk(a...) 0)
System is 997 kB
There are several obvious problems with this implementation:
* The KERN_ERR etc. macros can't work in all situations, since they are
no longer simple strings. The second patch fixes some of these
situations.
* Changing the printk symbol to be _printk is probably a bad idea. It
would be best to keep the symbol name the same in a real
implementation.
* It's somewhat hard to read.
Comments?
-J
--- include/linux/kernel.h-orig 2002-10-24 18:20:16.000000000 -0700
+++ include/linux/kernel.h 2002-10-24 18:23:36.000000000 -0700
@@ -13,6 +13,7 @@
#include <linux/types.h>
#include <linux/compiler.h>
#include <asm/byteorder.h>
+#include <linux/printk.h>
/* Optimization barrier */
/* The "volatile" is due to gcc bugs */
@@ -29,15 +30,6 @@
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-#define KERN_EMERG "<0>" /* system is unusable */
-#define KERN_ALERT "<1>" /* action must be taken immediately */
-#define KERN_CRIT "<2>" /* critical conditions */
-#define KERN_ERR "<3>" /* error conditions */
-#define KERN_WARNING "<4>" /* warning conditions */
-#define KERN_NOTICE "<5>" /* normal but significant condition */
-#define KERN_INFO "<6>" /* informational */
-#define KERN_DEBUG "<7>" /* debug-level messages */
-
struct completion;
#ifdef CONFIG_DEBUG_KERNEL
@@ -78,9 +70,6 @@
extern int session_of_pgrp(int pgrp);
-asmlinkage int printk(const char * fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-
extern int console_loglevel;
static inline void console_silent(void)
--- kernel/printk.c-orig 2002-10-24 18:57:06.000000000 -0700
+++ kernel/printk.c 2002-10-24 18:57:40.000000000 -0700
@@ -296,7 +296,7 @@
if (copy_from_user(lbuf, buf, len))
break;
lbuf[len] = '\0';
- error = printk("%s", lbuf);
+ error = _printk("%s", lbuf);
break;
default:
error = -EINVAL;
@@ -419,7 +419,7 @@
* then changes console_loglevel may break. This is because console_loglevel
* is inspected when the actual printing occurs.
*/
-asmlinkage int printk(const char *fmt, ...)
+asmlinkage int _printk(const char *fmt, ...)
{
va_list args;
unsigned long flags;
@@ -488,7 +488,7 @@
out:
return printed_len;
}
-EXPORT_SYMBOL(printk);
+EXPORT_SYMBOL(_printk);
/**
* acquire_console_sem - lock the console system for exclusive use.
--- /dev/null 2002-07-27 00:29:01.000000000 -0700
+++ include/linux/printk.h 2002-10-24 21:33:01.000000000 -0700
@@ -0,0 +1,150 @@
+#ifndef _LINUX_PRINTK_H
+#define _LINUX_PRINTK_H
+
+/*
+ * 'printk.h' contains some scary macros implementing compile-time
+ * selectable warning levels.
+ */
+
+#ifdef __KERNEL__
+
+#include <stdarg.h>
+#include <linux/linkage.h>
+
+/* Actual prepend strings */
+#define KERN_EMERG_STR "<0>" /* system is unusable */
+#define KERN_ALERT_STR "<1>" /* action must be taken immediately */
+#define KERN_CRIT_STR "<2>" /* critical conditions */
+#define KERN_ERR_STR "<3>" /* error conditions */
+#define KERN_WARNING_STR "<4>" /* warning conditions */
+#define KERN_NOTICE_STR "<5>" /* normal but significant condition */
+#define KERN_INFO_STR "<6>" /* informational */
+#define KERN_DEBUG_STR "<7>" /* debug-level messages */
+
+#define KERN_EMERG_LVL 0
+#define KERN_ALERT_LVL 1
+#define KERN_CRIT_LVL 2
+#define KERN_ERR_LVL 3
+#define KERN_WARNING_LVL 4
+#define KERN_NOTICE_LVL 5
+#define KERN_INFO_LVL 6
+#define KERN_DEBUG_LVL 7
+
+#if 1
+
+/* The operation of these macros is somewhat obscure. Basically, we
+ * depend on the optimizing compiler being able to remove branches
+ * that can never be followed because the expression is constant
+ * false.
+ *
+ * TAG_PRINTK_LVL and UNTAG_PRINTK_LVL may be changed at build time,
+ * allowing the user to compile printk statements below the listed
+ * level out completely.
+ *
+ * By default, they always succeed, so these macros should be (more or less)
+ * equivalent to standard printk calls.
+ *
+ * A possible problem on older versions of GCC is that, even if turned
+ * off, the actual strings may still be included in the object file.
+ */
+
+#if !defined(TAG_PRINTK_LVL)
+# define TAG_PRINTK_LVL 7
+#endif
+
+#if !defined(UNTAG_PRINTK_LVL)
+# define UNTAG_PRINTK_LVL 7
+#endif
+
+/* The trick here is that the a argument may be replaced by a KERN_
+ * macro, which will cause the UNTAG switch statement to disable itself.
+ * The kern macro will then place the proper level-based code in its own
+ * if statement.
+ */
+extern const char *__broken_printk_call;
+
+#define printk(a, arg...) ({ \
+ { \
+ int ret;\
+ if(TAG_PRINTK_LVL >= UNTAG_PRINTK_LVL) \
+ switch(UNTAG_PRINTK_LVL) { \
+ default: \
+ ret = _printk(0+ a, ##arg); \
+ } \
+ ret; \
+ } \
+})
+
+#define KERN_EMERG __broken_printk_call); \
+ case UNTAG_PRINTK_LVL: \
+ ret = 0; \
+ } \
+ if(TAG_PRINTK_LVL >= KERN_EMERG_LVL) { \
+ ret = _printk(KERN_EMERG_STR
+
+#define KERN_ALERT __broken_printk_call); \
+ case UNTAG_PRINTK_LVL: \
+ ret = 0; \
+ } \
+ if(TAG_PRINTK_LVL >= KERN_ALERT_LVL) { \
+ _printk(KERN_ALERT_STR
+
+#define KERN_CRIT __broken_printk_call); \
+ case UNTAG_PRINTK_LVL: \
+ ret = 0; \
+ } \
+ if(TAG_PRINTK_LVL >= KERN_CRIT_LVL) { \
+ _printk(KERN_CRIT_STR
+
+#define KERN_ERR __broken_printk_call); \
+ case UNTAG_PRINTK_LVL: \
+ ret = 0; \
+ } \
+ if(TAG_PRINTK_LVL >= KERN_ERR_LVL) { \
+ _printk(KERN_ERR_STR
+
+#define KERN_WARNING __broken_printk_call); \
+ case UNTAG_PRINTK_LVL: \
+ ret = 0; \
+ } \
+ if(TAG_PRINTK_LVL >= KERN_WARNING_LVL) { \
+ _printk(KERN_WARNING_STR
+
+#define KERN_NOTICE __broken_printk_call); \
+ case UNTAG_PRINTK_LVL: \
+ ret = 0; \
+ } \
+ if(TAG_PRINTK_LVL >= KERN_NOTICE_LVL) { \
+ _printk(KERN_NOTICE_STR
+
+#define KERN_INFO __broken_printk_call); \
+ case UNTAG_PRINTK_LVL: \
+ ret = 0; \
+ } \
+ if(TAG_PRINTK_LVL >= KERN_INFO_LVL) { \
+ _printk(KERN_INFO_STR
+
+#define KERN_DEBUG __broken_printk_call); \
+ case UNTAG_PRINTK_LVL: \
+ ret = 0; \
+ } \
+ if(TAG_PRINTK_LVL >= KERN_DEBUG_LVL) { \
+ _printk(KERN_DEBUG_STR
+#else
+#define printk(a, arg...) _printk(a, ##arg)
+#define KERN_EMERG KERN_EMERG_STR
+#define KERN_ALERT KERN_ALERT_STR
+#define KERN_CRIT KERN_CRIT_STR
+#define KERN_ERR KERN_ERR_STR
+#define KERN_WARNING KERN_WARNING_STR
+#define KERN_NOTICE KERN_NOTICE_STR
+#define KERN_INFO KERN_INFO_STR
+#define KERN_DEBUG KERN_DEBUG_STR
+#endif
+
+asmlinkage int _printk(const char * fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+#endif /* __KERNEL__ */
+
+#endif
^ permalink raw reply [flat|nested] 10+ messages in thread* Untested patch 2/2 - Fix some kernel sources for macro printk (was Re: [RFC] CONFIG_TINY)
2002-10-24 3:01 ` Elladan
2002-10-25 5:19 ` Untested patch 1/2 - add ugly printk macros to kernel (was Re: [RFC] CONFIG_TINY) Elladan
@ 2002-10-25 5:20 ` Elladan
1 sibling, 0 replies; 10+ messages in thread
From: Elladan @ 2002-10-25 5:20 UTC (permalink / raw)
To: Rasmus Andersen; +Cc: linux-kernel
The previous patch added some complex, ugly macros to replace printk()
in the kernel in a way which allows printk() calls to be selectively
disabled at compile time. These macros cannot work in all situations,
because some parts of the kernel depend on eg. KERN_ERR actually being a
simple string.
This patch modifies certain kernel sources to fix this. It either
removes the dependency, or changes these places to use a new
KERN_ERR_STR etc. macro.
This is not at all a complete patch - it was just the minimal change
required to get the core kernel to build with my own particular
configuration. I'm only including it since the previous patch doesn't
build at all without it.
-J
--- kernel/module.c-orig 2002-10-24 18:59:02.000000000 -0700
+++ kernel/module.c 2002-10-24 18:59:09.000000000 -0700
@@ -379,8 +379,8 @@
goto err1;
if (mod_user_size < (unsigned long)&((struct module *)0L)->persist_start
|| mod_user_size > sizeof(struct module) + 16*sizeof(void*)) {
- printk(KERN_ERR "init_module: Invalid module header size.\n"
- KERN_ERR "A new version of the modutils is likely "
+ printk(KERN_ERR "init_module: Invalid module header size.\n"
+ KERN_ERR_STR "A new version of the modutils is likely "
"needed.\n");
error = -EINVAL;
goto err1;
--- mm/slab.c-orig 2002-10-24 19:02:28.000000000 -0700
+++ mm/slab.c 2002-10-24 19:02:39.000000000 -0700
@@ -658,7 +658,7 @@
unsigned long flags, void (*ctor)(void*, kmem_cache_t *, unsigned long),
void (*dtor)(void*, kmem_cache_t *, unsigned long))
{
- const char *func_nm = KERN_ERR "kmem_create: ";
+ const char *func_nm = "kmem_create: ";
size_t left_over, align, slab_size;
kmem_cache_t *cachep = NULL;
@@ -676,13 +676,13 @@
#if DEBUG
if ((flags & SLAB_DEBUG_INITIAL) && !ctor) {
/* No constructor, but inital state check requested */
- printk("%sNo con, but init state check requested - %s\n", func_nm, name);
+ printk(KERN_ERR "%sNo con, but init state check requested - %s\n", func_nm, name);
flags &= ~SLAB_DEBUG_INITIAL;
}
if ((flags & SLAB_POISON) && ctor) {
/* request for poisoning, but we can't do that with a constructor */
- printk("%sPoisoning requested, but con given - %s\n", func_nm, name);
+ printk(KERN_ERR "%sPoisoning requested, but con given - %s\n", func_nm, name);
flags &= ~SLAB_POISON;
}
#if FORCED_DEBUG
@@ -717,7 +717,7 @@
if (size & (BYTES_PER_WORD-1)) {
size += (BYTES_PER_WORD-1);
size &= ~(BYTES_PER_WORD-1);
- printk("%sForcing size word alignment - %s\n", func_nm, name);
+ printk(KERN_ERR "%sForcing size word alignment - %s\n", func_nm, name);
}
#if DEBUG
@@ -788,7 +788,7 @@
} while (1);
if (!cachep->num) {
- printk("kmem_cache_create: couldn't create cache %s.\n", name);
+ printk(KERN_ERR "kmem_cache_create: couldn't create cache %s.\n", name);
kmem_cache_free(&cache_cache, cachep);
cachep = NULL;
goto opps;
--- drivers/md/md.c-orig 2002-10-24 19:07:52.000000000 -0700
+++ drivers/md/md.c 2002-10-24 19:12:17.000000000 -0700
@@ -56,7 +56,7 @@
#include <linux/blk.h>
#define DEBUG 0
-#define dprintk(x...) ((void)(DEBUG && printk(x)))
+#define dprintk(x...) do { if(DEBUG) printk(x); } while(0)
#ifndef MODULE
@@ -2977,7 +2977,7 @@
struct list_head *tmp, *rtmp;
- dprintk(KERN_INFO "md: recovery thread got woken up ...\n");
+ dprintk(KERN_INFO_STR "md: recovery thread got woken up ...\n");
ITERATE_MDDEV(mddev,tmp) if (mddev_lock(mddev)==0) {
if (!mddev->raid_disks || !mddev->pers || mddev->ro)
@@ -3054,7 +3054,7 @@
unlock:
mddev_unlock(mddev);
}
- dprintk(KERN_INFO "md: recovery thread finished ...\n");
+ dprintk(KERN_INFO_STR "md: recovery thread finished ...\n");
}
--- drivers/char/tty_io.c-orig 2002-10-24 19:06:14.000000000 -0700
+++ drivers/char/tty_io.c 2002-10-24 19:07:10.000000000 -0700
@@ -212,9 +212,9 @@
const char *routine)
{
#ifdef TTY_PARANOIA_CHECK
- static const char badmagic[] = KERN_WARNING
+ static const char badmagic[] = KERN_WARNING_STR
"Warning: bad magic number for tty struct (%s) in %s\n";
- static const char badtty[] = KERN_WARNING
+ static const char badtty[] = KERN_WARNING_STR
"Warning: null TTY for (%s) in %s\n";
if (!tty) {
--- drivers/block/floppy.c-orig 2002-10-24 19:04:29.000000000 -0700
+++ drivers/block/floppy.c 2002-10-24 19:05:46.000000000 -0700
@@ -3653,7 +3653,7 @@
if (name) {
const char * prepend = ",";
if (first) {
- prepend = KERN_INFO "Floppy drive(s):";
+ prepend = KERN_INFO_STR "Floppy drive(s):";
first = 0;
}
printk("%s fd%d is %s", prepend, drive, name);
--- net/sunrpc/sched.c-orig 2002-10-24 19:41:21.000000000 -0700
+++ net/sunrpc/sched.c 2002-10-24 19:41:35.000000000 -0700
@@ -338,7 +338,7 @@
} else {
rpc_clear_running(task);
if (task->tk_callback) {
- dprintk(KERN_ERR "RPC: %4d overwrites an active callback\n", task->tk_pid);
+ dprintk(KERN_ERR_STR "RPC: %4d overwrites an active callback\n", task->tk_pid);
BUG();
}
task->tk_callback = action;
--- net/sunrpc/clnt.c-orig 2002-10-24 19:35:53.000000000 -0700
+++ net/sunrpc/clnt.c 2002-10-24 19:39:59.000000000 -0700
@@ -909,7 +909,7 @@
task->tk_client->cl_stats->rpcgarbage++;
if (task->tk_garb_retry) {
task->tk_garb_retry--;
- dprintk(KERN_WARNING "RPC: garbage, retrying %4d\n", task->tk_pid);
+ dprintk(KERN_WARNING_STR "RPC: garbage, retrying %4d\n", task->tk_pid);
task->tk_action = call_encode;
return NULL;
}
--- net/sunrpc/svcsock.c-orig 2002-10-24 19:41:56.000000000 -0700
+++ net/sunrpc/svcsock.c 2002-10-24 19:42:31.000000000 -0700
@@ -715,7 +715,7 @@
* tell us anything. For now just warn about unpriv connections.
*/
if (ntohs(sin.sin_port) >= 1024) {
- dprintk(KERN_WARNING
+ dprintk(KERN_WARNING_STR
"%s: connect from unprivileged port: %u.%u.%u.%u:%d\n",
serv->sv_name,
NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port));
@@ -1304,7 +1304,7 @@
kfree(svsk);
} else {
spin_unlock_bh(&serv->sv_lock);
- dprintk(KERN_NOTICE "svc: server socket destroy delayed\n");
+ dprintk(KERN_NOTICE_STR "svc: server socket destroy delayed\n");
/* svsk->sk_server = NULL; */
}
}
--- net/core/netfilter.c-orig 2002-10-24 19:16:38.000000000 -0700
+++ net/core/netfilter.c 2002-10-24 19:18:45.000000000 -0700
@@ -584,15 +584,16 @@
fl.fl4_src = 0;
if ((err=ip_route_output_key(&rt, &fl)) != 0) {
+#ifdef CONFIG_IP_ROUTE_FWMARK
+#define FWMARK (*pskb)->nfmark
+#else
+#define FWMARK 0UL
+#endif
printk("route_me_harder: ip_route_output_key(dst=%u.%u.%u.%u, src=%u.%u.%u.%u, oif=%d, tos=0x%x, fwmark=0x%lx) error %d\n",
NIPQUAD(iph->daddr), NIPQUAD(iph->saddr),
(*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0,
RT_TOS(iph->tos)|RTO_CONN,
-#ifdef CONFIG_IP_ROUTE_FWMARK
- (*pskb)->nfmark,
-#else
- 0UL,
-#endif
+ FWMARK,
err);
goto out;
}
--- net/unix/af_unix.c-orig 2002-10-24 19:43:00.000000000 -0700
+++ net/unix/af_unix.c 2002-10-24 19:44:07.000000000 -0700
@@ -1882,7 +1882,8 @@
static inline void unix_sysctl_unregister(void) {}
#endif
-static char banner[] __initdata = KERN_INFO "NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.\n";
+static char banner[] __initdata = KERN_INFO_STR
+ "NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.\n";
static int __init af_unix_init(void)
{
--- net/ipv4/tcp_timer.c-orig 2002-10-24 19:19:27.000000000 -0700
+++ net/ipv4/tcp_timer.c 2002-10-24 19:19:48.000000000 -0700
@@ -35,7 +35,7 @@
static void tcp_delack_timer(unsigned long);
static void tcp_keepalive_timer (unsigned long data);
-const char timer_bug_msg[] = KERN_DEBUG "tcpbug: unknown timer value\n";
+const char timer_bug_msg[] = KERN_DEBUG_STR "tcpbug: unknown timer value\n";
/*
* Using different timers for retransmit, delayed acks and probes
--- arch/i386/kernel/head.S-orig 2002-10-24 19:45:20.000000000 -0700
+++ arch/i386/kernel/head.S 2002-10-24 19:45:41.000000000 -0700
@@ -323,7 +323,7 @@
movl %eax,%ds
movl %eax,%es
pushl $int_msg
- call printk
+ call _printk
popl %eax
popl %ds
popl %es
--- arch/i386/kernel/dmi_scan.c-orig 2002-10-24 18:55:01.000000000 -0700
+++ arch/i386/kernel/dmi_scan.c 2002-10-24 18:55:05.000000000 -0700
@@ -756,7 +756,7 @@
NO_MATCH, NO_MATCH, NO_MATCH
} },
- { print_if_true, KERN_WARNING "IBM T23 - BIOS 1.03b+ and controller firmware 1.02+ may be needed for Linux APM.", {
+ { print_if_true, KERN_WARNING_STR "IBM T23 - BIOS 1.03b+ and controller firmware 1.02+ may be needed for Linux APM.", {
MATCH(DMI_SYS_VENDOR, "IBM"),
MATCH(DMI_BIOS_VERSION, "1AET38WW (1.01b)"),
NO_MATCH, NO_MATCH
^ permalink raw reply [flat|nested] 10+ messages in thread