[Devel] [PATCH RH7 5/9] Port: diff-fence-watchdog-schedule-work -in-case-of-halt-action

Pavel Tikhomirov ptikhomirov at virtuozzo.com
Tue Oct 13 07:52:55 PDT 2015


move fence_wdog_check_timer check to dev_hard_start_xmit
from dev_hard_xmit

Author: Dmitry Guryanov
Email: dguryanov at parallels.com
Subject: WATCHDOG: schedule work in case of halt action
Date: Wed, 22 May 2013 13:50:53 +0400

It's not possible to do a halt or poweroff from
an atomic context. So let's schedule work and drop
all outgoing network packets after time exhausted.

fix for bug https://jira.sw.ru/browse/PSBM-20034

Signed-off-by: Dmitry Guryanov <dguryanov at parallels.com>
Acked-by: Stanislav Kinsbursky <skinsbursky at parallels.com>

Changes in v2:
	* don't specify cpu in schedule_work
	* use atomic_inc_not_zero instead of atomic_add_unless
	* return NETDEV_TX_OK instead of 0 from dev_hard_xmit

Changes in v3:
	* use halt instead of poweroff

Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
---
 include/linux/fence-watchdog.h |  2 +-
 kernel/fence-watchdog.c        | 35 ++++++++++++++++++++++++-----------
 net/core/dev.c                 | 14 +++++++++++---
 3 files changed, 36 insertions(+), 15 deletions(-)

diff --git a/include/linux/fence-watchdog.h b/include/linux/fence-watchdog.h
index 9cb41e9..b1e61bc 100644
--- a/include/linux/fence-watchdog.h
+++ b/include/linux/fence-watchdog.h
@@ -1,6 +1,6 @@
 #ifndef _LINUX_FENCE_WATCHDOG_H_
 #define _LINUX_FENCE_WATCHDOG_H_
 
-inline void fence_wdog_check_timer(void);
+inline int fence_wdog_check_timer(void);
 
 #endif
diff --git a/kernel/fence-watchdog.c b/kernel/fence-watchdog.c
index e65e73d..e7b7152 100644
--- a/kernel/fence-watchdog.c
+++ b/kernel/fence-watchdog.c
@@ -32,15 +32,27 @@ const char *action_names[] = {"crash", "reboot", "halt", NULL};
 
 DEFINE_VVAR(volatile unsigned long, fence_wdog_jiffies64) = MAX_U64;
 static int fence_wdog_action = FENCE_WDOG_CRASH;
+static atomic_t not_fenced = ATOMIC_INIT(-1);
+
+static void do_halt(struct work_struct *dummy)
+{
+	printk(KERN_EMERG"fence-watchdog: %s\n",
+	       action_names[fence_wdog_action]);
+	kernel_halt();
+}
+
+static DECLARE_WORK(halt_work, do_halt);
 
 void fence_wdog_do_fence(void)
 {
 	char *killer = NULL;
 
-	bust_spinlocks(1);
-	printk(KERN_EMERG"fence-watchdog: %s\n",
+	if (fence_wdog_action != FENCE_WDOG_POWEROFF) {
+		bust_spinlocks(1);
+		printk(KERN_EMERG"fence-watchdog: %s\n",
 			action_names[fence_wdog_action]);
-	bust_spinlocks(0);
+		bust_spinlocks(0);
+	}
 
 	switch (fence_wdog_action) {
 	case FENCE_WDOG_CRASH:
@@ -54,19 +66,20 @@ void fence_wdog_do_fence(void)
 		emergency_restart();
 		break;
 	case FENCE_WDOG_POWEROFF:
-		lockdep_off();
-		local_irq_enable();
-		sysdev_shutdown();
-		kmsg_dump(KMSG_DUMP_HALT);
-		machine_halt();
+		schedule_work(&halt_work);
 		break;
 	}
 }
 
-inline void fence_wdog_check_timer(void)
+inline int fence_wdog_check_timer(void)
 {
-	if (get_jiffies_64() > fence_wdog_jiffies64)
-		fence_wdog_do_fence();
+	if (unlikely(get_jiffies_64() > fence_wdog_jiffies64)) {
+		if (atomic_inc_not_zero(&not_fenced))
+			fence_wdog_do_fence();
+		return 1;
+	}
+
+	return 0;
 }
 
 static ssize_t fence_wdog_timer_show(struct kobject *kobj,
diff --git a/net/core/dev.c b/net/core/dev.c
index 5002d76..a8dd551 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2501,6 +2501,13 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
 	int rc = NETDEV_TX_OK;
 	unsigned int skb_len;
 
+#ifdef CONFIG_FENCE_WATCHDOG
+	if (unlikely(fence_wdog_check_timer())) {
+		kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+#endif
+
 	if (likely(!skb->next)) {
 		netdev_features_t features;
 
@@ -4282,6 +4289,10 @@ static void net_rx_action(struct softirq_action *h)
 
 	local_irq_disable();
 
+#ifdef CONFIG_FENCE_WATCHDOG
+	fence_wdog_check_timer();
+#endif
+
 	while (!list_empty(&sd->poll_list)) {
 		struct napi_struct *n;
 		int work, weight;
@@ -4352,9 +4363,6 @@ static void net_rx_action(struct softirq_action *h)
 out:
 	net_rps_action_and_irq_enable(sd);
 
-#ifdef CONFIG_FENCE_WATCHDOG
-	fence_wdog_check_timer();
-#endif
 	return;
 
 softnet_break:
-- 
1.9.3




More information about the Devel mailing list