fast-clean-shutdown-04.09.02.patch: This patch provides a fast system shutdown by freezing all processes, remounting all filesystems as read-only, closing all TCP connectinons, then powering down. Signed-off-by: Geoff Levand for CELF --- kernel/power/Kconfig | 5 ++++ kernel/power/main.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++ net/ipv4/tcp.c | 41 ++++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) diff -ruN -X ./dontdiff tag_FAST_CLEAN_SHUTDOWN_BASE/kernel/power/Kconfig branch_FAST_CLEAN_SHUTDOWN/kernel/power/Kconfig --- tag_FAST_CLEAN_SHUTDOWN_BASE/kernel/power/Kconfig 2004-09-02 15:18:19.000000000 -0700 +++ branch_FAST_CLEAN_SHUTDOWN/kernel/power/Kconfig 2004-09-02 15:20:54.000000000 -0700 @@ -24,6 +24,11 @@ ---help--- Mark Filesytem states clean on Suspend. +config FAST_CLEAN_SHUTDOWN + bool "Fast & Clean Shutdown (EXPERIMENTAL)" + depends on SAFE_SUSPEND + ---help--- + Mark file system states clean and close tcp connections on shutdown. config SOFTWARE_SUSPEND bool "Software Suspend (EXPERIMENTAL)" diff -ruN -X ./dontdiff tag_FAST_CLEAN_SHUTDOWN_BASE/kernel/power/main.c branch_FAST_CLEAN_SHUTDOWN/kernel/power/main.c --- tag_FAST_CLEAN_SHUTDOWN_BASE/kernel/power/main.c 2004-09-02 15:18:19.000000000 -0700 +++ branch_FAST_CLEAN_SHUTDOWN/kernel/power/main.c 2004-09-02 15:20:54.000000000 -0700 @@ -251,8 +251,69 @@ power_attr(state); +#ifdef CONFIG_FAST_CLEAN_SHUTDOWN + +#include +#include + +extern void tcp_shutdown_all(void); + +void fast_clean_shutdown(int fake_level) +{ + (void)freeze_processes(); + (void) suspend_remount(); + tcp_shutdown_all(); + + if (fake_level) + return; + + device_shutdown(); /* try to flush cache on device side */ + machine_power_off(); + + panic("fast_shutdown: can't power off\n"); + + /* NOTREACHED */ + +} + +static ssize_t fast_clean_shutdown_show(struct subsystem * subsys, char * buf) +{ + return sprintf(buf,"enabled\n"); +} + +static ssize_t fast_clean_shutdown_store(struct subsystem * subsys, const char * buf, + size_t n) +{ + + int fake_level; + char c; + + if (n>2) + return -EINVAL; + c = buf[1]; + if (c!='\0' && c!='\n') + return -EINVAL; + + c = buf[0]; + if (c == '0' || buf[0] == 'n' ) + return n; /* real fake */ + + fake_level = (buf[0] == '1' || buf[0] == 'y') ? 0 : 1; + fast_clean_shutdown(fake_level); + + return n; +} + +power_attr(fast_clean_shutdown); + + +#endif /* CONFIG_FAST_CLEAN_SHUTDOWN */ + static struct attribute * g[] = { &state_attr.attr, +#ifdef CONFIG_FAST_CLEAN_SHUTDOWN + &fast_clean_shutdown_attr.attr, +#endif NULL, }; diff -ruN -X ./dontdiff tag_FAST_CLEAN_SHUTDOWN_BASE/net/ipv4/tcp.c branch_FAST_CLEAN_SHUTDOWN/net/ipv4/tcp.c --- tag_FAST_CLEAN_SHUTDOWN_BASE/net/ipv4/tcp.c 2004-09-02 15:18:19.000000000 -0700 +++ branch_FAST_CLEAN_SHUTDOWN/net/ipv4/tcp.c 2004-09-02 15:21:00.000000000 -0700 @@ -2186,6 +2186,47 @@ return 0; } +#ifdef CONFIG_FAST_CLEAN_SHUTDOWN + +void tcp_shutdown_all(void) +{ + int bucket; + + for (bucket = 0; bucket < tcp_ehash_size; ++bucket) { + struct sock *sk; + struct hlist_node *node, *t; + + read_lock(&tcp_ehash[bucket].lock); + sk_for_each_safe(sk, node, t, &tcp_ehash[bucket].chain) { + read_unlock(&tcp_ehash[bucket].lock); + + switch(sk->sk_family) { + case PF_INET: + if (LOOPBACK(htonl(inet_sk(sk)->daddr))) + continue; + break; +#ifdef CONFIG_IPV6 + case PF_INET6: + if (ipv6_addr_type(&inet6_sk(sk)->daddr) + & IPV6_ADDR_LOOPBACK) + continue; + break; +#endif + default: + continue; + } + + tcp_shutdown(sk, SEND_SHUTDOWN); + + read_lock(&tcp_ehash[bucket].lock); + } + read_unlock(&tcp_ehash[bucket].lock); + + } +} + +#endif /* CONFIG_FAST_CLEAN_SHUTDOWN */ + extern void __skb_cb_too_small_for_tcp(int, int); extern void tcpdiag_init(void);