diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2006-12-13 03:33:50 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-13 12:05:47 -0500 |
commit | eff3b634d9a0cccb6ca8b431819fa415f10804dc (patch) | |
tree | 8bf2dac62ce9c4e4aa62ea5a66831ed65ef35137 /arch/um/drivers/net_kern.c | |
parent | ffd22b8e08fb86692d316cdcc1a4da4d10a016c5 (diff) |
[PATCH] uml: fix net_kern workqueue abuse
Fix up the work on stack and exit scope trouble by placing the work_struct
in the uml_net_private data.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Acked-by: Jeff Dike <jdike@addtoit.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/um/drivers/net_kern.c')
-rw-r--r-- | arch/um/drivers/net_kern.c | 15 |
1 files changed, 9 insertions, 6 deletions
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index b2e9762e13c5..afe3d427ddfa 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c | |||
@@ -72,9 +72,11 @@ static int uml_net_rx(struct net_device *dev) | |||
72 | return pkt_len; | 72 | return pkt_len; |
73 | } | 73 | } |
74 | 74 | ||
75 | static void uml_dev_close(void* dev) | 75 | static void uml_dev_close(struct work_struct *work) |
76 | { | 76 | { |
77 | dev_close( (struct net_device *) dev); | 77 | struct uml_net_private *lp = |
78 | container_of(work, struct uml_net_private, work); | ||
79 | dev_close(lp->dev); | ||
78 | } | 80 | } |
79 | 81 | ||
80 | irqreturn_t uml_net_interrupt(int irq, void *dev_id) | 82 | irqreturn_t uml_net_interrupt(int irq, void *dev_id) |
@@ -89,7 +91,6 @@ irqreturn_t uml_net_interrupt(int irq, void *dev_id) | |||
89 | spin_lock(&lp->lock); | 91 | spin_lock(&lp->lock); |
90 | while((err = uml_net_rx(dev)) > 0) ; | 92 | while((err = uml_net_rx(dev)) > 0) ; |
91 | if(err < 0) { | 93 | if(err < 0) { |
92 | DECLARE_WORK(close_work, uml_dev_close, dev); | ||
93 | printk(KERN_ERR | 94 | printk(KERN_ERR |
94 | "Device '%s' read returned %d, shutting it down\n", | 95 | "Device '%s' read returned %d, shutting it down\n", |
95 | dev->name, err); | 96 | dev->name, err); |
@@ -97,9 +98,10 @@ irqreturn_t uml_net_interrupt(int irq, void *dev_id) | |||
97 | * again lp->lock. | 98 | * again lp->lock. |
98 | * And dev_close() can be safely called multiple times on the | 99 | * And dev_close() can be safely called multiple times on the |
99 | * same device, since it tests for (dev->flags & IFF_UP). So | 100 | * same device, since it tests for (dev->flags & IFF_UP). So |
100 | * there's no harm in delaying the device shutdown. */ | 101 | * there's no harm in delaying the device shutdown. |
101 | schedule_work(&close_work); | 102 | * Furthermore, the workqueue will not re-enqueue an already |
102 | #error this is not permitted - close_work will go out of scope | 103 | * enqueued work item. */ |
104 | schedule_work(&lp->work); | ||
103 | goto out; | 105 | goto out; |
104 | } | 106 | } |
105 | reactivate_fd(lp->fd, UM_ETH_IRQ); | 107 | reactivate_fd(lp->fd, UM_ETH_IRQ); |
@@ -365,6 +367,7 @@ static int eth_configure(int n, void *init, char *mac, | |||
365 | /* This points to the transport private data. It's still clear, but we | 367 | /* This points to the transport private data. It's still clear, but we |
366 | * must memset it to 0 *now*. Let's help the drivers. */ | 368 | * must memset it to 0 *now*. Let's help the drivers. */ |
367 | memset(lp, 0, size); | 369 | memset(lp, 0, size); |
370 | INIT_WORK(&lp->work, uml_dev_close); | ||
368 | 371 | ||
369 | /* sysfs register */ | 372 | /* sysfs register */ |
370 | if (!driver_registered) { | 373 | if (!driver_registered) { |