[ovs-dev] [PATCH 5/7] datapath: Backport workqueue functions.

Jesse Gross jesse at nicira.com
Mon Sep 20 18:13:43 UTC 2010


An upcoming commit will use some workqueue functions that weren't
available on earlier kernels, so this backports those functions.
The backporting uses timers instead of delayed work queues because
the earlier versions of work queues have some unsafe corner cases.
In addition, this removes some unused work queue backporting code
that is no longer used because it is potentially unsafe.

Signed-off-by: Jesse Gross <jesse at nicira.com>
---
 datapath/datapath.c                                |    1 -
 .../linux-2.6/compat-2.6/include/linux/workqueue.h |   61 +++++++++----------
 2 files changed, 29 insertions(+), 33 deletions(-)

diff --git a/datapath/datapath.c b/datapath/datapath.c
index d6c2410..a47fba2 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -39,7 +39,6 @@
 #include <linux/inetdevice.h>
 #include <linux/list.h>
 #include <linux/rculist.h>
-#include <linux/workqueue.h>
 #include <linux/dmi.h>
 #include <net/inet_ecn.h>
 #include <linux/compat.h>
diff --git a/datapath/linux-2.6/compat-2.6/include/linux/workqueue.h b/datapath/linux-2.6/compat-2.6/include/linux/workqueue.h
index 1ac3b6e..b5af05f 100644
--- a/datapath/linux-2.6/compat-2.6/include/linux/workqueue.h
+++ b/datapath/linux-2.6/compat-2.6/include/linux/workqueue.h
@@ -4,39 +4,36 @@
 #include_next <linux/workqueue.h>
 
 #include <linux/version.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
 
-#ifdef __KERNEL__
-/*
- * initialize a work-struct's func and data pointers:
+/* Older kernels have an implementation of work queues with some very bad
+ * characteristics when trying to cancel work (potential deadlocks, use after
+ * free, etc.  Here we directly use timers instead for delayed work.  It's not
+ * optimal but it is better than the alternative.
  */
-#undef PREPARE_WORK
-#define PREPARE_WORK(_work, _func)                              \
-        do {                                                    \
-		(_work)->func = (void(*)(void*)) _func;		\
-                (_work)->data = _work;				\
-        } while (0)
-
-/*
- * initialize all of a work-struct:
- */
-#undef INIT_WORK
-#define INIT_WORK(_work, _func)                                 \
-        do {                                                    \
-                INIT_LIST_HEAD(&(_work)->entry);                \
-                (_work)->pending = 0;                           \
-                PREPARE_WORK((_work), (_func));                 \
-                init_timer(&(_work)->timer);                    \
-        } while (0)
-
-#endif /* __KERNEL__ */
-
-#endif /* linux kernel < 2.6.20 */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
-/* There is no equivalent to cancel_work_sync() so just flush all
- * pending work. */
-#define cancel_work_sync(_work) flush_scheduled_work()
-#endif
+
+#include <linux/timer.h>
+
+#undef DECLARE_DELAYED_WORK
+#define DECLARE_DELAYED_WORK(n, f) \
+	struct timer_list n = TIMER_INITIALIZER((void (*)(unsigned long))f, 0, 0)
+
+#define schedule_delayed_work rpl_schedule_delayed_work
+static inline int schedule_delayed_work(struct timer_list *timer, unsigned long delay)
+{
+	if (timer_pending(timer))
+		return 0;
+
+	mod_timer(timer, jiffies + delay);
+	return 1;
+}
+
+#define cancel_delayed_work_sync rpl_cancel_delayed_work_sync
+static inline int cancel_delayed_work_sync(struct timer_list *timer)
+{
+	return del_timer_sync(timer);
+}
+
+#endif /* kernel version < 2.6.23 */
 
 #endif
-- 
1.7.0.4





More information about the dev mailing list