Patch from chas williams this patch changes the atm_dev_lock spinlock to a semaphore. this solves the sleeping while holding a spinlock problem. none of the code paths doing the original locking are in_interrupt() so this is fairly straight forward. atm/addr.c | 1 - atm/common.c | 21 +++++++++++---------- atm/resources.c | 17 +++++++++-------- atm/signaling.c | 7 ++++--- 4 files changed, 24 insertions(+), 22 deletions(-) diff -puN net/atm/addr.c~atm_dev_sem net/atm/addr.c --- 25/net/atm/addr.c~atm_dev_sem 2003-02-22 15:16:37.000000000 -0800 +++ 25-akpm/net/atm/addr.c 2003-02-22 15:16:37.000000000 -0800 @@ -42,7 +42,6 @@ static int identical(struct sockaddr_atm */ static DECLARE_MUTEX(local_lock); -extern spinlock_t atm_dev_lock; static void notify_sigd(struct atm_dev *dev) { diff -puN net/atm/common.c~atm_dev_sem net/atm/common.c --- 25/net/atm/common.c~atm_dev_sem 2003-02-22 15:16:37.000000000 -0800 +++ 25-akpm/net/atm/common.c 2003-02-22 15:16:37.000000000 -0800 @@ -27,6 +27,7 @@ #include #include #include +#include #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) #include @@ -79,7 +80,7 @@ EXPORT_SYMBOL(pppoatm_ioctl_hook); #define DPRINTK(format,args...) #endif -spinlock_t atm_dev_lock = SPIN_LOCK_UNLOCKED; +DECLARE_MUTEX(atm_dev_sem); static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size) { @@ -145,7 +146,7 @@ void atm_release_vcc_sk(struct sock *sk, vcc->dev->ops->free_rx_skb(vcc,skb); else kfree_skb(skb); } - spin_lock (&atm_dev_lock); + down(&atm_dev_sem); fops_put (vcc->dev->ops); if (atomic_read(&vcc->rx_inuse)) printk(KERN_WARNING "atm_release_vcc: strange ... " @@ -153,11 +154,11 @@ void atm_release_vcc_sk(struct sock *sk, atomic_read(&vcc->rx_inuse)); bind_vcc(vcc,NULL); } else - spin_lock (&atm_dev_lock); + down(&atm_dev_sem); if (free_sk) free_atm_vcc_sk(sk); - spin_unlock (&atm_dev_lock); + up(&atm_dev_sem); } @@ -268,14 +269,14 @@ static int atm_do_connect(struct atm_vcc struct atm_dev *dev; int return_val; - spin_lock (&atm_dev_lock); + down(&atm_dev_sem); dev = atm_find_dev(itf); if (!dev) return_val = -ENODEV; else return_val = atm_do_connect_dev(vcc,dev,vpi,vci); - spin_unlock (&atm_dev_lock); + up(&atm_dev_sem); return return_val; } @@ -307,10 +308,10 @@ int atm_connect_vcc(struct atm_vcc *vcc, else { struct atm_dev *dev; - spin_lock (&atm_dev_lock); + down(&atm_dev_sem); for (dev = atm_devs; dev; dev = dev->next) if (!atm_do_connect_dev(vcc,dev,vpi,vci)) break; - spin_unlock (&atm_dev_lock); + up(&atm_dev_sem); if (!dev) return -ENODEV; } if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) @@ -552,7 +553,7 @@ int atm_ioctl(struct socket *sock,unsign int error,len,size,number, ret_val; ret_val = 0; - spin_lock (&atm_dev_lock); + down(&atm_dev_sem); vcc = ATM_SD(sock); switch (cmd) { case SIOCOUTQ: @@ -942,7 +943,7 @@ int atm_ioctl(struct socket *sock,unsign ret_val = 0; done: - spin_unlock (&atm_dev_lock); + up(&atm_dev_sem); return ret_val; } diff -puN net/atm/resources.c~atm_dev_sem net/atm/resources.c --- 25/net/atm/resources.c~atm_dev_sem 2003-02-22 15:16:37.000000000 -0800 +++ 25-akpm/net/atm/resources.c 2003-02-22 15:16:37.000000000 -0800 @@ -16,6 +16,7 @@ #include #include #include /* for struct sock */ +#include #include "common.h" #include "resources.h" @@ -29,9 +30,9 @@ struct atm_dev *atm_devs = NULL; static struct atm_dev *last_dev = NULL; struct atm_vcc *nodev_vccs = NULL; -extern spinlock_t atm_dev_lock; +extern struct semaphore atm_dev_sem; -/* Caller must hold atm_dev_lock. */ +/* Caller must hold atm_dev_sem. */ static struct atm_dev *__alloc_atm_dev(const char *type) { struct atm_dev *dev; @@ -56,7 +57,7 @@ static struct atm_dev *__alloc_atm_dev(c return dev; } -/* Caller must hold atm_dev_lock. */ +/* Caller must hold atm_dev_sem. */ static void __free_atm_dev(struct atm_dev *dev) { if (dev->prev) @@ -70,7 +71,7 @@ static void __free_atm_dev(struct atm_de kfree(dev); } -/* Caller must hold atm_dev_lock. */ +/* Caller must hold atm_dev_sem. */ struct atm_dev *atm_find_dev(int number) { struct atm_dev *dev; @@ -87,7 +88,7 @@ struct atm_dev *atm_dev_register(const c { struct atm_dev *dev; - spin_lock(&atm_dev_lock); + down(&atm_dev_sem); dev = __alloc_atm_dev(type); if (!dev) { @@ -131,7 +132,7 @@ struct atm_dev *atm_dev_register(const c #endif done: - spin_unlock(&atm_dev_lock); + up(&atm_dev_sem); return dev; } @@ -142,9 +143,9 @@ void atm_dev_deregister(struct atm_dev * if (dev->ops->proc_read) atm_proc_dev_deregister(dev); #endif - spin_lock(&atm_dev_lock); + down(&atm_dev_sem); __free_atm_dev(dev); - spin_unlock(&atm_dev_lock); + up(&atm_dev_sem); } void shutdown_atm_dev(struct atm_dev *dev) diff -puN net/atm/signaling.c~atm_dev_sem net/atm/signaling.c --- 25/net/atm/signaling.c~atm_dev_sem 2003-02-22 15:16:37.000000000 -0800 +++ 25-akpm/net/atm/signaling.c 2003-02-22 15:16:37.000000000 -0800 @@ -13,6 +13,7 @@ #include #include #include +#include #include "resources.h" #include "signaling.h" @@ -33,7 +34,7 @@ struct atm_vcc *sigd = NULL; static DECLARE_WAIT_QUEUE_HEAD(sigd_sleep); -extern spinlock_t atm_dev_lock; +extern struct semaphore atm_dev_sem; static void sigd_put_skb(struct sk_buff *skb) { @@ -220,9 +221,9 @@ static void sigd_close(struct atm_vcc *v skb_queue_purge(&vcc->recvq); purge_vccs(nodev_vccs); - spin_lock (&atm_dev_lock); + down(&atm_dev_sem); for (dev = atm_devs; dev; dev = dev->next) purge_vccs(dev->vccs); - spin_unlock (&atm_dev_lock); + up(&atm_dev_sem); } _