move fence_wdog_check_timer check to dev_hard_start_xmit
from dev_hard_xmit

Author: Dmitry Guryanov
Email: dgurya...@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 <dgurya...@parallels.com>
Acked-by: Stanislav Kinsbursky <skinsbur...@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 <ptikhomi...@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

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to