Re: PROBLEM: Consistent lock up on >=2.6.8

From: Andrew Morton
Date: Mon Oct 04 2004 - 22:55:46 EST


Roland Dreier <roland@xxxxxxxxxxx> wrote:
>
> @@ -2375,7 +2372,7 @@ void ip_vs_control_cleanup(void)
> {
> EnterFunction(2);
> ip_vs_trash_cleanup();
> - del_timer_sync(&defense_timer);
> + cancel_delayed_work(&defense_work);
>
> Do we need a flush_scheduled_work() here to be totally safe? Not sure
> if it could ever really happen but it seems the module could at least
> theoretically be unloaded with update_defense_level() still running...

Excellent point. We don't appear to have a function which does that.

How does this look?

(It's probably wrong, actually. THis stuff's tricky. In particular, the
work handler *has* to re-add the delayed work, 100% of the time.)




Add library functions to reliably kill off a delayed work whose handler
re-adds the delayed work. One for keventd, one for caller-owned workqueues.

Signed-off-by: Andrew Morton <akpm@xxxxxxxx>
---

25-akpm/include/linux/workqueue.h | 3 +++
25-akpm/kernel/workqueue.c | 25 +++++++++++++++++++++++++
2 files changed, 28 insertions(+)

diff -puN kernel/workqueue.c~cancel_rearming_delayed_work kernel/workqueue.c
--- 25/kernel/workqueue.c~cancel_rearming_delayed_work 2004-10-04 20:48:23.397238464 -0700
+++ 25-akpm/kernel/workqueue.c 2004-10-04 20:48:23.402237704 -0700
@@ -423,6 +423,31 @@ void flush_scheduled_work(void)
flush_workqueue(keventd_wq);
}

+/**
+ * cancel_rearming_delayed_workqueue - reliably kill off a delayed
+ * work whose handler rearms the delayed work.
+ * @wq: the controlling workqueue structure
+ * @work: the delayed work struct
+ */
+void cancel_rearming_delayed_workqueue(struct workqueue_struct *wq,
+ struct work_struct *work)
+{
+ while (!cancel_delayed_work(work))
+ flush_workqueue(wq);
+}
+EXPORT_SYMBOL(cancel_rearming_delayed_workqueue);
+
+/**
+ * cancel_rearming_delayed_work - reliably kill off a delayed keventd
+ * work whose handler rearms the delayed work.
+ * @work: the delayed work struct
+ */
+void cancel_rearming_delayed_work(struct work_struct *work)
+{
+ cancel_rearming_delayed_workqueue(keventd_wq, work);
+}
+EXPORT_SYMBOL(cancel_rearming_delayed_work);
+
int keventd_up(void)
{
return keventd_wq != NULL;
diff -puN include/linux/workqueue.h~cancel_rearming_delayed_work include/linux/workqueue.h
--- 25/include/linux/workqueue.h~cancel_rearming_delayed_work 2004-10-04 20:48:23.398238312 -0700
+++ 25-akpm/include/linux/workqueue.h 2004-10-04 20:48:23.403237552 -0700
@@ -70,6 +70,9 @@ extern int current_is_keventd(void);
extern int keventd_up(void);

extern void init_workqueues(void);
+void cancel_rearming_delayed_workqueue(struct workqueue_struct *wq,
+ struct work_struct *work);
+void cancel_rearming_delayed_work(struct work_struct *work);

/*
* Kill off a pending schedule_delayed_work(). Note that the work callback
_

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/