2002-10-11 01:36:15

by Tim Hockin

[permalink] [raw]
Subject: PATCH idea

===== drivers/net/net_init.c 1.9 vs edited =====
--- 1.9/drivers/net/net_init.c Mon Feb 4 23:44:55 2002
+++ edited/drivers/net/net_init.c Thu Oct 10 11:44:18 2002
@@ -93,6 +93,7 @@
dev->priv = (void *) (((long)(dev + 1) + 31) & ~31);

setup(dev);
+ INIT_WORK(&dev->link_work, NULL, NULL);
strcpy(dev->name, mask);

return dev;
@@ -163,6 +164,7 @@
*/

setup(dev);
+ INIT_WORK(&dev->link_work, NULL, NULL);

if (new_device) {
int err;
===== include/linux/netdevice.h 1.24 vs edited =====
--- 1.24/include/linux/netdevice.h Fri Oct 4 19:17:35 2002
+++ edited/include/linux/netdevice.h Thu Oct 10 14:56:23 2002
@@ -35,6 +35,7 @@

#ifdef __KERNEL__
#include <linux/config.h>
+#include <linux/workqueue.h>
#ifdef CONFIG_NET_PROFILE
#include <net/profile.h>
#endif
@@ -437,6 +438,7 @@
/* this will get initialized at each interface type init routine */
struct divert_blk *divert;
#endif /* CONFIG_NET_DIVERT */
+ struct work_struct link_work;
};


@@ -637,17 +639,20 @@
}

extern void __netdev_watchdog_up(struct net_device *dev);
+extern void netdev_do_link_work(struct net_device *dev);

static inline void netif_carrier_on(struct net_device *dev)
{
clear_bit(__LINK_STATE_NOCARRIER, &dev->state);
if (netif_running(dev))
__netdev_watchdog_up(dev);
+ netdev_do_link_work(dev);
}

static inline void netif_carrier_off(struct net_device *dev)
{
set_bit(__LINK_STATE_NOCARRIER, &dev->state);
+ netdev_do_link_work(dev);
}

/* Hot-plugging. */
===== include/linux/workqueue.h 1.3 vs edited =====
--- 1.3/include/linux/workqueue.h Thu Oct 3 14:29:58 2002
+++ edited/include/linux/workqueue.h Thu Oct 10 16:50:36 2002
@@ -7,6 +7,7 @@

#include <linux/timer.h>
#include <linux/linkage.h>
+#include <linux/spinlock.h>

struct workqueue_struct;

@@ -17,12 +18,15 @@
void *data;
void *wq_data;
struct timer_list timer;
+ spinlock_t lock;
};

#define __WORK_INITIALIZER(n, f, d) { \
.entry = { &(n).entry, &(n).entry }, \
+ .pending = 0, \
.func = (f), \
- .data = (d) }
+ .data = (d), \
+ .lock = SPIN_LOCK_UNLOCKED }

#define DECLARE_WORK(n, f, d) \
struct work_struct n = __WORK_INITIALIZER(n, f, d)
@@ -45,6 +49,7 @@
(_work)->pending = 0; \
PREPARE_WORK((_work), (_func), (_data)); \
init_timer(&(_work)->timer); \
+ spin_lock_init(&(_work)->lock); \
} while (0)

extern struct workqueue_struct *create_workqueue(const char *name);
@@ -56,10 +61,13 @@

extern int FASTCALL(schedule_work(struct work_struct *work));
extern int FASTCALL(schedule_delayed_work(struct work_struct *work, unsigned long delay));
+extern int FASTCALL(cancel_work(struct work_struct *work));
extern void flush_scheduled_work(void);
extern int current_is_keventd(void);

extern void init_workqueues(void);
+
+#define work_pending(_work) test_bit(0, &(_work)->pending)

#endif

===== kernel/workqueue.c 1.3 vs edited =====
--- 1.3/kernel/workqueue.c Thu Oct 3 05:37:56 2002
+++ edited/kernel/workqueue.c Thu Oct 10 17:12:28 2002
@@ -140,10 +140,13 @@
void *data = work->data;

list_del_init(cwq->worklist.next);
- spin_unlock_irqrestore(&cwq->lock, flags);
+ spin_lock(&work->lock);
+ spin_unlock(&cwq->lock);

BUG_ON(work->wq_data != cwq);
clear_bit(0, &work->pending);
+ spin_unlock_irqrestore(&work->lock, flags);
+
f(data);

/*
@@ -354,6 +357,28 @@
flush_workqueue(keventd_wq);
}

+int cancel_work(struct work_struct *work)
+{
+ unsigned long flags;
+ struct cpu_workqueue_struct *cwq;
+ int cancelled = 0;
+
+ /* this should be safe to read - it only races with queue_*work() */
+ cwq = work->wq_data;
+
+ spin_lock_irqsave(&cwq->lock, flags);
+ spin_lock(&work->lock);
+ if (work_pending(work)) {
+ list_del_init(&work->entry);
+ clear_bit(0, &work->pending);
+ cancelled = 1;
+ }
+ spin_unlock(&work->lock);
+ spin_unlock_irqrestore(&cwq->lock, flags);
+
+ return cancelled;
+}
+
int current_is_keventd(void)
{
struct cpu_workqueue_struct *cwq;
@@ -386,4 +411,5 @@
EXPORT_SYMBOL(schedule_work);
EXPORT_SYMBOL(schedule_delayed_work);
EXPORT_SYMBOL(flush_scheduled_work);
+EXPORT_SYMBOL(cancel_work);

===== net/netsyms.c 1.29 vs edited =====
--- 1.29/net/netsyms.c Fri Oct 4 19:17:35 2002
+++ edited/net/netsyms.c Thu Oct 10 14:57:53 2002
@@ -471,6 +471,7 @@
EXPORT_SYMBOL(register_netdevice);
EXPORT_SYMBOL(unregister_netdevice);
EXPORT_SYMBOL(netdev_state_change);
+EXPORT_SYMBOL(netdev_do_link_work);
EXPORT_SYMBOL(dev_new_index);
EXPORT_SYMBOL(dev_get_by_index);
EXPORT_SYMBOL(__dev_get_by_index);
===== net/core/dev.c 1.41 vs edited =====
--- 1.41/net/core/dev.c Mon Oct 7 05:31:06 2002
+++ edited/net/core/dev.c Thu Oct 10 16:05:06 2002
@@ -629,6 +629,20 @@
}
}

+static void do_link_work(void *cookie)
+{
+ struct net_device *dev = cookie;
+ rtnl_lock();
+ rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_RUNNING);
+ rtnl_unlock();
+}
+
+void netdev_do_link_work(struct net_device *dev)
+{
+ cancel_work(&dev->link_work);
+ PREPARE_WORK(&dev->link_work, do_link_work, dev);
+ schedule_work(&dev->link_work);
+}

#ifdef CONFIG_KMOD


Attachments:
link_change_via_netlink.diff (4.98 kB)