From 1cab3f9fcc7ecaf70c77a10032b4757f769e345b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 21 Dec 2012 17:56:53 -0800 Subject: [PATCH 01/11] sja1000: don't use [delayed_]work_pending() There's no need to test whether a (delayed) work item in pending before queueing, flushing or cancelling it. Most uses are unnecessary and quite a few of them are buggy. Remove unnecessary pending tests from sja1000. Only compile tested. Signed-off-by: Tejun Heo Acked-by: "David S. Miller" Cc: Wolfgang Grandegger Cc: netdev@vger.kernel.org --- drivers/net/can/sja1000/peak_pci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/can/sja1000/peak_pci.c b/drivers/net/can/sja1000/peak_pci.c index d84888f03d92..600ac7226e5c 100644 --- a/drivers/net/can/sja1000/peak_pci.c +++ b/drivers/net/can/sja1000/peak_pci.c @@ -339,8 +339,7 @@ static void peak_pciec_set_leds(struct peak_pciec_card *card, u8 led_mask, u8 s) */ static void peak_pciec_start_led_work(struct peak_pciec_card *card) { - if (!delayed_work_pending(&card->led_work)) - schedule_delayed_work(&card->led_work, HZ); + schedule_delayed_work(&card->led_work, HZ); } /* From 7f5855c979ef0d49a8680b7fbdd3fc8e3093cb73 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 21 Dec 2012 17:56:57 -0800 Subject: [PATCH 02/11] mwifiex: don't use [delayed_]work_pending() Drop work_pending() test from mwifiex_sdio_card_reset(). As work_pending() becomes %false before sdio_card_reset_worker() starts executing, it doesn't really protect anything. reset_host may change between mmc_remove_host() and mmc_add_host(). Make sdio_card_reset_worker() cache the target mmc_host so that it isn't affected by mwifiex_sdio_card_reset() racing with it. Only compile tested. Signed-off-by: Tejun Heo Acked-by: Bing Zhao Cc: linux-wireless@vger.kernel.org --- drivers/net/wireless/mwifiex/sdio.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 5a1c1d0e5599..f2874c3392b4 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -1752,6 +1752,8 @@ mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port) static struct mmc_host *reset_host; static void sdio_card_reset_worker(struct work_struct *work) { + struct mmc_host *target = reset_host; + /* The actual reset operation must be run outside of driver thread. * This is because mmc_remove_host() will cause the device to be * instantly destroyed, and the driver then needs to end its thread, @@ -1761,10 +1763,10 @@ static void sdio_card_reset_worker(struct work_struct *work) */ pr_err("Resetting card...\n"); - mmc_remove_host(reset_host); + mmc_remove_host(target); /* 20ms delay is based on experiment with sdhci controller */ mdelay(20); - mmc_add_host(reset_host); + mmc_add_host(target); } static DECLARE_WORK(card_reset_work, sdio_card_reset_worker); @@ -1773,9 +1775,6 @@ static void mwifiex_sdio_card_reset(struct mwifiex_adapter *adapter) { struct sdio_mmc_card *card = adapter->card; - if (work_pending(&card_reset_work)) - return; - reset_host = card->func->card->host; schedule_work(&card_reset_work); } From 6d394e192541a106bf78f361e2c4e586a8344e3e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 21 Dec 2012 17:56:58 -0800 Subject: [PATCH 03/11] thinkpad_acpi: don't use [delayed_]work_pending() There's no need to test whether a (delayed) work item in pending before queueing, flushing or cancelling it. Most uses are unnecessary and quite a few of them are buggy. Remove unnecessary pending tests from thinkpad_acpi. Only compile tested. Signed-off-by: Tejun Heo Acked-by: Henrique de Moraes Holschuh Cc: ibm-acpi-devel@lists.sourceforge.net Cc: platform-driver-x86@vger.kernel.org --- drivers/platform/x86/thinkpad_acpi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 75dd651664ae..8421d1e7e47c 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -4877,8 +4877,7 @@ static int __init light_init(struct ibm_init_struct *iibm) static void light_exit(void) { led_classdev_unregister(&tpacpi_led_thinklight.led_classdev); - if (work_pending(&tpacpi_led_thinklight.work)) - flush_workqueue(tpacpi_wq); + flush_workqueue(tpacpi_wq); } static int light_read(struct seq_file *m) From 02957f92bcc96be5c84a4000f9d22c592158602e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 21 Dec 2012 17:56:59 -0800 Subject: [PATCH 04/11] wl1251: don't use [delayed_]work_pending() There's no need to test whether a (delayed) work item in pending before queueing, flushing or cancelling it. Most uses are unnecessary and quite a few of them are buggy. Remove unnecessary pending tests from wl1251. Only compile tested. Signed-off-by: Tejun Heo Acked-by: Luciano Coelho Cc: linux-wireless@vger.kernel.org --- drivers/net/wireless/ti/wl1251/ps.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/ti/wl1251/ps.c b/drivers/net/wireless/ti/wl1251/ps.c index db719f7d2692..b9e27b98bbc9 100644 --- a/drivers/net/wireless/ti/wl1251/ps.c +++ b/drivers/net/wireless/ti/wl1251/ps.c @@ -68,8 +68,7 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl) unsigned long timeout, start; u32 elp_reg; - if (delayed_work_pending(&wl->elp_work)) - cancel_delayed_work(&wl->elp_work); + cancel_delayed_work(&wl->elp_work); if (!wl->elp) return 0; From ba0c96cd9a361693b0bae409510d614dc0e26d0f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 21 Dec 2012 17:57:04 -0800 Subject: [PATCH 05/11] rfkill: don't use [delayed_]work_pending() There's no need to test whether a (delayed) work item in pending before queueing, flushing or cancelling it. Most uses are unnecessary and quite a few of them are buggy. Remove unnecessary pending tests from rfkill. Only compile tested. Signed-off-by: Tejun Heo Acked-by: Johannes Berg Cc: "John W. Linville" Cc: linux-wireless@vger.kernel.org --- net/rfkill/input.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/net/rfkill/input.c b/net/rfkill/input.c index c9d931e7ffec..b85107b5ef62 100644 --- a/net/rfkill/input.c +++ b/net/rfkill/input.c @@ -148,11 +148,9 @@ static unsigned long rfkill_ratelimit(const unsigned long last) static void rfkill_schedule_ratelimited(void) { - if (delayed_work_pending(&rfkill_op_work)) - return; - schedule_delayed_work(&rfkill_op_work, - rfkill_ratelimit(rfkill_last_scheduled)); - rfkill_last_scheduled = jiffies; + if (schedule_delayed_work(&rfkill_op_work, + rfkill_ratelimit(rfkill_last_scheduled))) + rfkill_last_scheduled = jiffies; } static void rfkill_schedule_global_op(enum rfkill_sched_op op) From 4d899be584d4b4c5d6b49d655176b25cebf6ff1a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 21 Dec 2012 17:57:05 -0800 Subject: [PATCH 06/11] x86/mce: don't use [delayed_]work_pending() There's no need to test whether a (delayed) work item in pending before queueing, flushing or cancelling it. Most uses are unnecessary and quite a few of them are buggy. Remove unnecessary pending tests from x86/mce. Only compile tested. v2: Local var work removed from mce_schedule_work() as suggested by Borislav. Signed-off-by: Tejun Heo Acked-by: Borislav Petkov Cc: Tony Luck Cc: linux-edac@vger.kernel.org --- arch/x86/kernel/cpu/mcheck/mce.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 80dbda84f1c3..fc7608a89d93 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -512,11 +512,8 @@ int mce_available(struct cpuinfo_x86 *c) static void mce_schedule_work(void) { - if (!mce_ring_empty()) { - struct work_struct *work = &__get_cpu_var(mce_work); - if (!work_pending(work)) - schedule_work(work); - } + if (!mce_ring_empty()) + schedule_work(&__get_cpu_var(mce_work)); } DEFINE_PER_CPU(struct irq_work, mce_irq_work); @@ -1351,12 +1348,7 @@ int mce_notify_irq(void) /* wake processes polling /dev/mcelog */ wake_up_interruptible(&mce_chrdev_wait); - /* - * There is no risk of missing notifications because - * work_pending is always cleared before the function is - * executed. - */ - if (mce_helper[0] && !work_pending(&mce_trigger_work)) + if (mce_helper[0]) schedule_work(&mce_trigger_work); if (__ratelimit(&ratelimit)) From 7998005bf7a706a1d6bb3cf2e9783b6437e4419d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 21 Dec 2012 17:57:11 -0800 Subject: [PATCH 07/11] tty/max3100: don't use [delayed_]work_pending() There's no need to test whether a (delayed) work item in pending before queueing, flushing or cancelling it. Most uses are unnecessary and quite a few of them are buggy. Remove unnecessary pending tests from max3100. Only compile tested. Signed-off-by: Tejun Heo Acked-by: Greg Kroah-Hartman Cc: Jiri Slaby --- drivers/tty/serial/max3100.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 7ce3197087bb..dd6277eb5a38 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -179,8 +179,7 @@ static void max3100_work(struct work_struct *w); static void max3100_dowork(struct max3100_port *s) { - if (!s->force_end_work && !work_pending(&s->work) && - !freezing(current) && !s->suspending) + if (!s->force_end_work && !freezing(current) && !s->suspending) queue_work(s->workqueue, &s->work); } From 7d0315a2bec2dd7fe9cbe31098bb89536648224e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 21 Dec 2012 17:57:13 -0800 Subject: [PATCH 08/11] video/exynos: don't use [delayed_]work_pending() There's no need to test whether a (delayed) work item in pending before queueing, flushing or cancelling it. Most uses are unnecessary and quite a few of them are buggy. Remove unnecessary pending tests from exynos_dp_core. Only compile tested. Signed-off-by: Tejun Heo Acked-by: Kukjin Kim Acked-by: Jingoo Han --- drivers/video/exynos/exynos_dp_core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c index 28fd686c6b81..3002a6acce12 100644 --- a/drivers/video/exynos/exynos_dp_core.c +++ b/drivers/video/exynos/exynos_dp_core.c @@ -1121,8 +1121,7 @@ static int __devexit exynos_dp_remove(struct platform_device *pdev) disable_irq(dp->irq); - if (work_pending(&dp->hotplug_work)) - flush_work(&dp->hotplug_work); + flush_work(&dp->hotplug_work); if (pdev->dev.of_node) { if (dp->phy_addr) @@ -1144,8 +1143,7 @@ static int exynos_dp_suspend(struct device *dev) struct exynos_dp_platdata *pdata = dev->platform_data; struct exynos_dp_device *dp = dev_get_drvdata(dev); - if (work_pending(&dp->hotplug_work)) - flush_work(&dp->hotplug_work); + flush_work(&dp->hotplug_work); if (dev->of_node) { if (dp->phy_addr) From 7c99e0bf86fdc1dee238eb6e213b980f887b68f1 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 21 Dec 2012 17:56:54 -0800 Subject: [PATCH 09/11] ipw2x00: simplify scan_event handling * Drop unnesssary delayd_work_pending() tests. * Unify scan_event_{now|later} by using mod_delayed_work() w/ 0 delay for scan_event_now. * Make ipw2200 scan_event handling match ipw2100 - use mod_delayed_work() w/ 0 delay for immediate scanning. Only compile tested. Signed-off-by: Tejun Heo Acked-by: Stanislav Yakovlev Cc: linux-wireless@vger.kernel.org --- drivers/net/wireless/ipw2x00/ipw2100.c | 31 +++++++------------------- drivers/net/wireless/ipw2x00/ipw2100.h | 3 +-- drivers/net/wireless/ipw2x00/ipw2200.c | 13 +++-------- 3 files changed, 12 insertions(+), 35 deletions(-) diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index d92b21a8e597..b3ab7b7becae 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -2181,9 +2181,10 @@ static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status) mod_delayed_work(system_wq, &priv->rf_kill, round_jiffies_relative(HZ)); } -static void send_scan_event(void *data) +static void ipw2100_scan_event(struct work_struct *work) { - struct ipw2100_priv *priv = data; + struct ipw2100_priv *priv = container_of(work, struct ipw2100_priv, + scan_event.work); union iwreq_data wrqu; wrqu.data.length = 0; @@ -2191,18 +2192,6 @@ static void send_scan_event(void *data) wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL); } -static void ipw2100_scan_event_later(struct work_struct *work) -{ - send_scan_event(container_of(work, struct ipw2100_priv, - scan_event_later.work)); -} - -static void ipw2100_scan_event_now(struct work_struct *work) -{ - send_scan_event(container_of(work, struct ipw2100_priv, - scan_event_now)); -} - static void isr_scan_complete(struct ipw2100_priv *priv, u32 status) { IPW_DEBUG_SCAN("scan complete\n"); @@ -2212,13 +2201,11 @@ static void isr_scan_complete(struct ipw2100_priv *priv, u32 status) /* Only userspace-requested scan completion events go out immediately */ if (!priv->user_requested_scan) { - if (!delayed_work_pending(&priv->scan_event_later)) - schedule_delayed_work(&priv->scan_event_later, - round_jiffies_relative(msecs_to_jiffies(4000))); + schedule_delayed_work(&priv->scan_event, + round_jiffies_relative(msecs_to_jiffies(4000))); } else { priv->user_requested_scan = 0; - cancel_delayed_work(&priv->scan_event_later); - schedule_work(&priv->scan_event_now); + mod_delayed_work(system_wq, &priv->scan_event, 0); } } @@ -4459,8 +4446,7 @@ static void ipw2100_kill_works(struct ipw2100_priv *priv) cancel_delayed_work_sync(&priv->wx_event_work); cancel_delayed_work_sync(&priv->hang_check); cancel_delayed_work_sync(&priv->rf_kill); - cancel_work_sync(&priv->scan_event_now); - cancel_delayed_work_sync(&priv->scan_event_later); + cancel_delayed_work_sync(&priv->scan_event); } static int ipw2100_tx_allocate(struct ipw2100_priv *priv) @@ -6195,8 +6181,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, INIT_DELAYED_WORK(&priv->wx_event_work, ipw2100_wx_event_work); INIT_DELAYED_WORK(&priv->hang_check, ipw2100_hang_check); INIT_DELAYED_WORK(&priv->rf_kill, ipw2100_rf_kill); - INIT_WORK(&priv->scan_event_now, ipw2100_scan_event_now); - INIT_DELAYED_WORK(&priv->scan_event_later, ipw2100_scan_event_later); + INIT_DELAYED_WORK(&priv->scan_event, ipw2100_scan_event); tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) ipw2100_irq_tasklet, (unsigned long)priv); diff --git a/drivers/net/wireless/ipw2x00/ipw2100.h b/drivers/net/wireless/ipw2x00/ipw2100.h index 5fe17cbab1f3..c6d78790cb0d 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.h +++ b/drivers/net/wireless/ipw2x00/ipw2100.h @@ -577,8 +577,7 @@ struct ipw2100_priv { struct delayed_work wx_event_work; struct delayed_work hang_check; struct delayed_work rf_kill; - struct work_struct scan_event_now; - struct delayed_work scan_event_later; + struct delayed_work scan_event; int user_requested_scan; diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 844f201b7b70..2c2d6db0536c 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -4480,18 +4480,11 @@ static void handle_scan_event(struct ipw_priv *priv) { /* Only userspace-requested scan completion events go out immediately */ if (!priv->user_requested_scan) { - if (!delayed_work_pending(&priv->scan_event)) - schedule_delayed_work(&priv->scan_event, - round_jiffies_relative(msecs_to_jiffies(4000))); + schedule_delayed_work(&priv->scan_event, + round_jiffies_relative(msecs_to_jiffies(4000))); } else { - union iwreq_data wrqu; - priv->user_requested_scan = 0; - cancel_delayed_work(&priv->scan_event); - - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL); + mod_delayed_work(system_wq, &priv->scan_event, 0); } } From ad72b3bea744b4db01c89af0f86f3e8920d354df Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 21 Dec 2012 17:57:00 -0800 Subject: [PATCH 10/11] kprobes: fix wait_for_kprobe_optimizer() wait_for_kprobe_optimizer() seems largely broken. It uses optimizer_comp which is never re-initialized, so wait_for_kprobe_optimizer() will never wait for anything once kprobe_optimizer() finishes all pending jobs for the first time. Also, aside from completion, delayed_work_pending() is %false once kprobe_optimizer() starts execution and wait_for_kprobe_optimizer() won't wait for it. Reimplement it so that it flushes optimizing_work until [un]optimizing_lists are empty. Note that this also makes optimizing_work execute immediately if someone's waiting for it, which is the nicer behavior. Only compile tested. Signed-off-by: Tejun Heo Acked-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Anil S Keshavamurthy Cc: "David S. Miller" --- kernel/kprobes.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 098f396aa409..f230e81a9db6 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -471,7 +471,6 @@ static LIST_HEAD(unoptimizing_list); static void kprobe_optimizer(struct work_struct *work); static DECLARE_DELAYED_WORK(optimizing_work, kprobe_optimizer); -static DECLARE_COMPLETION(optimizer_comp); #define OPTIMIZE_DELAY 5 /* @@ -552,8 +551,7 @@ static __kprobes void do_free_cleaned_kprobes(struct list_head *free_list) /* Start optimizer after OPTIMIZE_DELAY passed */ static __kprobes void kick_kprobe_optimizer(void) { - if (!delayed_work_pending(&optimizing_work)) - schedule_delayed_work(&optimizing_work, OPTIMIZE_DELAY); + schedule_delayed_work(&optimizing_work, OPTIMIZE_DELAY); } /* Kprobe jump optimizer */ @@ -592,16 +590,25 @@ static __kprobes void kprobe_optimizer(struct work_struct *work) /* Step 5: Kick optimizer again if needed */ if (!list_empty(&optimizing_list) || !list_empty(&unoptimizing_list)) kick_kprobe_optimizer(); - else - /* Wake up all waiters */ - complete_all(&optimizer_comp); } /* Wait for completing optimization and unoptimization */ static __kprobes void wait_for_kprobe_optimizer(void) { - if (delayed_work_pending(&optimizing_work)) - wait_for_completion(&optimizer_comp); + mutex_lock(&kprobe_mutex); + + while (!list_empty(&optimizing_list) || !list_empty(&unoptimizing_list)) { + mutex_unlock(&kprobe_mutex); + + /* this will also make optimizing_work execute immmediately */ + flush_delayed_work(&optimizing_work); + /* @optimizing_work might not have been queued yet, relax */ + cpu_relax(); + + mutex_lock(&kprobe_mutex); + } + + mutex_unlock(&kprobe_mutex); } /* Optimize kprobe if p is ready to be optimized */ From 23663c873154f01220ef679558e1ca110c4c4ca4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 21 Dec 2012 17:57:10 -0800 Subject: [PATCH 11/11] wimax/i2400m: fix i2400m->wake_tx_skb handling i2400m_net_wake_tx() sets ->wake_tx_skb with the given skb if ->wake_tx_ws is not pending; however, i2400m_wake_tx_work() could have just started execution and haven't fetched ->wake_tx_skb handling. * i2400m_net_wake_tx() now tests whether the previous ->wake_tx_skb has been consumed by ->wake_tx_ws instead of testing work_pending(). * i2400m_net_wake_stop() is simplified similarly. It always puts ->wake_tx_skb if non-NULL. * Spurious ->wake_tx_skb dereference outside critical section dropped from i2400m_wake_tx_work(). Only compile tested. Signed-off-by: Tejun Heo Acked-by: Dan Williams Cc: Inaky Perez-Gonzalez Cc: linux-wimax@intel.com Cc: wimax@linuxwimax.org --- drivers/net/wimax/i2400m/netdev.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c index 1d76ae855f07..530581ca0191 100644 --- a/drivers/net/wimax/i2400m/netdev.c +++ b/drivers/net/wimax/i2400m/netdev.c @@ -156,7 +156,7 @@ void i2400m_wake_tx_work(struct work_struct *ws) struct i2400m *i2400m = container_of(ws, struct i2400m, wake_tx_ws); struct net_device *net_dev = i2400m->wimax_dev.net_dev; struct device *dev = i2400m_dev(i2400m); - struct sk_buff *skb = i2400m->wake_tx_skb; + struct sk_buff *skb; unsigned long flags; spin_lock_irqsave(&i2400m->tx_lock, flags); @@ -236,23 +236,26 @@ void i2400m_tx_prep_header(struct sk_buff *skb) void i2400m_net_wake_stop(struct i2400m *i2400m) { struct device *dev = i2400m_dev(i2400m); + struct sk_buff *wake_tx_skb; + unsigned long flags; d_fnstart(3, dev, "(i2400m %p)\n", i2400m); - /* See i2400m_hard_start_xmit(), references are taken there - * and here we release them if the work was still - * pending. Note we can't differentiate work not pending vs - * never scheduled, so the NULL check does that. */ - if (cancel_work_sync(&i2400m->wake_tx_ws) == 0 - && i2400m->wake_tx_skb != NULL) { - unsigned long flags; - struct sk_buff *wake_tx_skb; - spin_lock_irqsave(&i2400m->tx_lock, flags); - wake_tx_skb = i2400m->wake_tx_skb; /* compat help */ - i2400m->wake_tx_skb = NULL; /* compat help */ - spin_unlock_irqrestore(&i2400m->tx_lock, flags); + /* + * See i2400m_hard_start_xmit(), references are taken there and + * here we release them if the packet was still pending. + */ + cancel_work_sync(&i2400m->wake_tx_ws); + + spin_lock_irqsave(&i2400m->tx_lock, flags); + wake_tx_skb = i2400m->wake_tx_skb; + i2400m->wake_tx_skb = NULL; + spin_unlock_irqrestore(&i2400m->tx_lock, flags); + + if (wake_tx_skb) { i2400m_put(i2400m); kfree_skb(wake_tx_skb); } + d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); } @@ -288,7 +291,7 @@ int i2400m_net_wake_tx(struct i2400m *i2400m, struct net_device *net_dev, * and if pending, release those resources. */ result = 0; spin_lock_irqsave(&i2400m->tx_lock, flags); - if (!work_pending(&i2400m->wake_tx_ws)) { + if (!i2400m->wake_tx_skb) { netif_stop_queue(net_dev); i2400m_get(i2400m); i2400m->wake_tx_skb = skb_get(skb); /* transfer ref count */