diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/um/drivers/net_kern.c | 15 |
1 files changed, 13 insertions, 2 deletions
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index f3442ce29a21..8ebb2241ad42 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -68,6 +68,11 @@ static int uml_net_rx(struct net_device *dev) return pkt_len; } +static void uml_dev_close(void* dev) +{ + dev_close( (struct net_device *) dev); +} + irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; @@ -80,15 +85,21 @@ irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) spin_lock(&lp->lock); while((err = uml_net_rx(dev)) > 0) ; if(err < 0) { + DECLARE_WORK(close_work, uml_dev_close, dev); printk(KERN_ERR "Device '%s' read returned %d, shutting it down\n", dev->name, err); - dev_close(dev); + /* dev_close can't be called in interrupt context, and takes + * again lp->lock. + * And dev_close() can be safely called multiple times on the + * same device, since it tests for (dev->flags & IFF_UP). So + * there's no harm in delaying the device shutdown. */ + schedule_work(&close_work); goto out; } reactivate_fd(lp->fd, UM_ETH_IRQ); - out: +out: spin_unlock(&lp->lock); return(IRQ_HANDLED); } |