From a586df067afe0580bb02b7a6312ca2afe49bba03 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Sat, 21 Jul 2007 17:10:00 +0200 Subject: x86: Support __attribute__((__cold__)) in gcc 4.3 gcc 4.3 supports a new __attribute__((__cold__)) to mark functions cold. Any path directly leading to a call of this function will be unlikely. And gcc will try to generate smaller code for the function itself. Please use with care. The code generation advantage isn't large and in most cases it is not worth uglifying code with this. This patch marks some common error functions like panic(), printk() as cold. This will longer term make many unlikely()s unnecessary, although we can keep them for now for older compilers. BUG is not marked cold because there is currently no way to tell gcc to mark a inline function told. Also all __init and __exit functions are marked cold. With a non -Os build this will tell the compiler to generate slightly smaller code for them. I think it currently only uses less alignments for labels, but that might change in the future. One disadvantage over *likely() is that they cannot be easily instrumented to verify them. Another drawback is that only the latest gcc 4.3 snapshots support this. Unfortunately we cannot detect this using the preprocessor. This means older snapshots will fail now. I don't think that's a problem because they are unreleased compilers that nobody should be using. gcc also has a __hot__ attribute, but I don't see any sense in using this in the kernel right now. But someday I hope gcc will be able to use more aggressive optimizing for hot functions even in -Os, if that happens it should be added. Includes compile fix from Thomas Gleixner. Cc: Jan Hubicka Signed-off-by: Andi Kleen Signed-off-by: Linus Torvalds --- include/linux/init.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'include/linux/init.h') diff --git a/include/linux/init.h b/include/linux/init.h index 5b5285316339..f0d0e3295a9b 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -40,10 +40,10 @@ /* These are for everybody (although not all archs will actually discard it in modules) */ -#define __init __attribute__ ((__section__ (".init.text"))) +#define __init __attribute__ ((__section__ (".init.text"))) __cold #define __initdata __attribute__ ((__section__ (".init.data"))) #define __exitdata __attribute__ ((__section__(".exit.data"))) -#define __exit_call __attribute_used__ __attribute__ ((__section__ (".exitcall.exit"))) +#define __exit_call __attribute_used__ __attribute__ ((__section__ (".exitcall.exit"))) __cold /* modpost check for section mismatches during the kernel build. * A section mismatch happens when there are references from a @@ -59,9 +59,9 @@ #define __initdata_refok __attribute__ ((__section__ (".data.init.refok"))) #ifdef MODULE -#define __exit __attribute__ ((__section__(".exit.text"))) +#define __exit __attribute__ ((__section__(".exit.text"))) __cold #else -#define __exit __attribute_used__ __attribute__ ((__section__(".exit.text"))) +#define __exit __attribute_used__ __attribute__ ((__section__(".exit.text"))) __cold #endif /* For assembly routines */ -- cgit v1.2.3-71-gd317 From 73dd1166af9a7a1e24554991236ddea740df0dbd Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 31 Jul 2007 00:38:54 -0700 Subject: pure_initcall ID inconsistency pure_initcall uses the same ID as core_initcall. I guess that's a typo and it should use its own ID. Signed-off-by: Michael Buesch Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/init.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux/init.h') diff --git a/include/linux/init.h b/include/linux/init.h index f0d0e3295a9b..1a4a283d19a9 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -114,7 +114,7 @@ void prepare_namespace(void); * * This only exists for built-in code, not for modules. */ -#define pure_initcall(fn) __define_initcall("0",fn,1) +#define pure_initcall(fn) __define_initcall("0",fn,0) #define core_initcall(fn) __define_initcall("1",fn,1) #define core_initcall_sync(fn) __define_initcall("1s",fn,1s) -- cgit v1.2.3-71-gd317 From 3f3f7b74a7749c3a669ca146270c07568b548665 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Fri, 10 Aug 2007 22:31:01 +0200 Subject: x86_64: Don't mark __exitcall as __cold gcc currently doesn't support attributes on types, so we can't use it function pointers. This avoids some warnings on a gcc 4.3 build. Signed-off-by: Andi Kleen Signed-off-by: Linus Torvalds --- include/linux/init.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux/init.h') diff --git a/include/linux/init.h b/include/linux/init.h index 1a4a283d19a9..74b1f43bf982 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -43,7 +43,7 @@ #define __init __attribute__ ((__section__ (".init.text"))) __cold #define __initdata __attribute__ ((__section__ (".init.data"))) #define __exitdata __attribute__ ((__section__(".exit.data"))) -#define __exit_call __attribute_used__ __attribute__ ((__section__ (".exitcall.exit"))) __cold +#define __exit_call __attribute_used__ __attribute__ ((__section__ (".exitcall.exit"))) /* modpost check for section mismatches during the kernel build. * A section mismatch happens when there are references from a -- cgit v1.2.3-71-gd317 From 4665079cbb2a3e17de82f2ab2940b9f97f37d65e Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 8 Oct 2007 20:38:39 -0700 Subject: [NETNS]: Move some code into __init section when CONFIG_NET_NS=n With the net namespaces many code leaved the __init section, thus making the kernel occupy more memory than it did before. Since we have a config option that prohibits the namespace creation, the functions that initialize/finalize some netns stuff are simply not needed and can be freed after the boot. Currently, this is almost not noticeable, since few calls are no longer in __init, but when the namespaces will be merged it will be possible to free more code. I propose to use the __net_init, __net_exit and __net_initdata "attributes" for functions/variables that are not used if the CONFIG_NET_NS is not set to save more space in memory. The exiting functions cannot just reside in the __exit section, as noticed by David, since the init section will have references on it and the compilation will fail due to modpost checks. These references can exist, since the init namespace never dies and the exit callbacks are never called. So I introduce the __exit_refok attribute just like it is already done with the __init_refok. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- drivers/net/loopback.c | 6 +++--- fs/proc/proc_net.c | 8 ++++---- include/linux/init.h | 1 + include/net/net_namespace.h | 9 +++++++++ net/core/dev.c | 16 ++++++++-------- net/core/dev_mcast.c | 6 +++--- net/netlink/af_netlink.c | 6 +++--- scripts/mod/modpost.c | 1 + 8 files changed, 32 insertions(+), 21 deletions(-) (limited to 'include/linux/init.h') diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index d6997aec45dd..be25aa33971c 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -250,7 +250,7 @@ static void loopback_setup(struct net_device *dev) } /* Setup and register the loopback device. */ -static int loopback_net_init(struct net *net) +static __net_init int loopback_net_init(struct net *net) { struct net_device *dev; int err; @@ -278,14 +278,14 @@ out_free_netdev: goto out; } -static void loopback_net_exit(struct net *net) +static __net_exit void loopback_net_exit(struct net *net) { struct net_device *dev = net->loopback_dev; unregister_netdev(dev); } -static struct pernet_operations loopback_net_ops = { +static struct pernet_operations __net_initdata loopback_net_ops = { .init = loopback_net_init, .exit = loopback_net_exit, }; diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c index 85cc8e8bb862..2e91fb756e9a 100644 --- a/fs/proc/proc_net.c +++ b/fs/proc/proc_net.c @@ -140,7 +140,7 @@ static struct inode_operations proc_net_dir_inode_operations = { .setattr = proc_net_setattr, }; -static int proc_net_ns_init(struct net *net) +static __net_init int proc_net_ns_init(struct net *net) { struct proc_dir_entry *root, *netd, *net_statd; int err; @@ -178,19 +178,19 @@ free_root: goto out; } -static void proc_net_ns_exit(struct net *net) +static __net_exit void proc_net_ns_exit(struct net *net) { remove_proc_entry("stat", net->proc_net); remove_proc_entry("net", net->proc_net_root); kfree(net->proc_net_root); } -struct pernet_operations proc_net_ns_ops = { +struct pernet_operations __net_initdata proc_net_ns_ops = { .init = proc_net_ns_init, .exit = proc_net_ns_exit, }; -int proc_net_init(void) +int __init proc_net_init(void) { proc_net_shadow = proc_mkdir("net", NULL); proc_net_shadow->proc_iops = &proc_net_dir_inode_operations; diff --git a/include/linux/init.h b/include/linux/init.h index 74b1f43bf982..f8d9d0b5cffc 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -57,6 +57,7 @@ * The markers follow same syntax rules as __init / __initdata. */ #define __init_refok noinline __attribute__ ((__section__ (".text.init.refok"))) #define __initdata_refok __attribute__ ((__section__ (".data.init.refok"))) +#define __exit_refok noinline __attribute__ ((__section__ (".exit.text.refok"))) #ifdef MODULE #define __exit __attribute__ ((__section__(".exit.text"))) __cold diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 934c840b5941..93aa87d32804 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -99,6 +99,15 @@ static inline void release_net(struct net *net) #define for_each_net(VAR) \ list_for_each_entry(VAR, &net_namespace_list, list) +#ifdef CONFIG_NET_NS +#define __net_init +#define __net_exit +#define __net_initdata +#else +#define __net_init __init +#define __net_exit __exit_refok +#define __net_initdata __initdata +#endif struct pernet_operations { struct list_head list; diff --git a/net/core/dev.c b/net/core/dev.c index 1aa07047826e..e7e728aea9f3 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2611,7 +2611,7 @@ static const struct file_operations ptype_seq_fops = { }; -static int dev_proc_net_init(struct net *net) +static int __net_init dev_proc_net_init(struct net *net) { int rc = -ENOMEM; @@ -2636,7 +2636,7 @@ out_dev: goto out; } -static void dev_proc_net_exit(struct net *net) +static void __net_exit dev_proc_net_exit(struct net *net) { wext_proc_exit(net); @@ -2645,7 +2645,7 @@ static void dev_proc_net_exit(struct net *net) proc_net_remove(net, "dev"); } -static struct pernet_operations dev_proc_ops = { +static struct pernet_operations __net_initdata dev_proc_ops = { .init = dev_proc_net_init, .exit = dev_proc_net_exit, }; @@ -4278,7 +4278,7 @@ static struct hlist_head *netdev_create_hash(void) } /* Initialize per network namespace state */ -static int netdev_init(struct net *net) +static int __net_init netdev_init(struct net *net) { INIT_LIST_HEAD(&net->dev_base_head); rwlock_init(&dev_base_lock); @@ -4299,18 +4299,18 @@ err_name: return -ENOMEM; } -static void netdev_exit(struct net *net) +static void __net_exit netdev_exit(struct net *net) { kfree(net->dev_name_head); kfree(net->dev_index_head); } -static struct pernet_operations netdev_net_ops = { +static struct pernet_operations __net_initdata netdev_net_ops = { .init = netdev_init, .exit = netdev_exit, }; -static void default_device_exit(struct net *net) +static void __net_exit default_device_exit(struct net *net) { struct net_device *dev, *next; /* @@ -4336,7 +4336,7 @@ static void default_device_exit(struct net *net) rtnl_unlock(); } -static struct pernet_operations default_device_ops = { +static struct pernet_operations __net_initdata default_device_ops = { .exit = default_device_exit, }; diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c index 896b0ca5aed7..15241cf48af8 100644 --- a/net/core/dev_mcast.c +++ b/net/core/dev_mcast.c @@ -273,19 +273,19 @@ static const struct file_operations dev_mc_seq_fops = { #endif -static int dev_mc_net_init(struct net *net) +static int __net_init dev_mc_net_init(struct net *net) { if (!proc_net_fops_create(net, "dev_mcast", 0, &dev_mc_seq_fops)) return -ENOMEM; return 0; } -static void dev_mc_net_exit(struct net *net) +static void __net_exit dev_mc_net_exit(struct net *net) { proc_net_remove(net, "dev_mcast"); } -static struct pernet_operations dev_mc_net_ops = { +static struct pernet_operations __net_initdata dev_mc_net_ops = { .init = dev_mc_net_init, .exit = dev_mc_net_exit, }; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 46eb5ea1fbd7..3ef32825da71 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1924,7 +1924,7 @@ static struct net_proto_family netlink_family_ops = { .owner = THIS_MODULE, /* for consistency 8) */ }; -static int netlink_net_init(struct net *net) +static int __net_init netlink_net_init(struct net *net) { #ifdef CONFIG_PROC_FS if (!proc_net_fops_create(net, "netlink", 0, &netlink_seq_fops)) @@ -1933,14 +1933,14 @@ static int netlink_net_init(struct net *net) return 0; } -static void netlink_net_exit(struct net *net) +static void __net_exit netlink_net_exit(struct net *net) { #ifdef CONFIG_PROC_FS proc_net_remove(net, "netlink"); #endif } -static struct pernet_operations netlink_net_ops = { +static struct pernet_operations __net_initdata netlink_net_ops = { .init = netlink_net_init, .exit = netlink_net_exit, }; diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 6c145d6e89de..0a4051fbd34e 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -709,6 +709,7 @@ static int secref_whitelist(const char *modname, const char *tosec, /* Check for pattern 0 */ if ((strncmp(fromsec, ".text.init.refok", strlen(".text.init.refok")) == 0) || + (strncmp(fromsec, ".exit.text.refok", strlen(".exit.text.refok")) == 0) || (strncmp(fromsec, ".data.init.refok", strlen(".data.init.refok")) == 0)) return 1; -- cgit v1.2.3-71-gd317