public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] atmrefcount
@ 2000-11-22  9:31 Patrick van de Lageweg
  2000-11-22 16:03 ` Mitchell Blank Jr
  0 siblings, 1 reply; 6+ messages in thread
From: Patrick van de Lageweg @ 2000-11-22  9:31 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Linux Kernel Mailing List, Rogier Wolff

Hi Linus,

This patch contains the fix for the atmrefcount problem (noted as a
critical problem in Ted's todo list). It also has the makefile
modifications for the firestream driver in a separate email. 


	Patrick

diff -u -r linux-2.4.0-test11.clean/drivers/atm/Config.in linux-2.4.0-test11.fs50+atmrefcount/drivers/atm/Config.in
--- linux-2.4.0-test11.clean/drivers/atm/Config.in	Wed Jul 12 12:24:48 2000
+++ linux-2.4.0-test11.fs50+atmrefcount/drivers/atm/Config.in	Wed Nov 22 08:59:12 2000
@@ -22,6 +22,7 @@
 	 bool '    Enable 2W RX bursts (optional)' CONFIG_ATM_ENI_BURST_RX_2W
       fi
    fi
+   tristate 'Fujitsu FireStream (FS50/FS155) ' CONFIG_ATM_FIRESTREAM
    tristate 'ZeitNet ZN1221/ZN1225' CONFIG_ATM_ZATM
    if [ "$CONFIG_ATM_ZATM" != "n" ]; then
       bool '  Enable extended debugging' CONFIG_ATM_ZATM_DEBUG
diff -u -r linux-2.4.0-test11.clean/drivers/atm/Makefile linux-2.4.0-test11.fs50+atmrefcount/drivers/atm/Makefile
--- linux-2.4.0-test11.clean/drivers/atm/Makefile	Sun Aug  6 20:23:40 2000
+++ linux-2.4.0-test11.fs50+atmrefcount/drivers/atm/Makefile	Wed Nov 22 08:59:12 2000
@@ -19,6 +19,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_ATM_FIRESTREAM),y)
+O_OBJS += firestream.o
+else
+  ifeq ($(CONFIG_ATM_FIRESTREAM),m)
+  M_OBJS += firestream.o
+  endif
+endif
+
 ifeq ($(CONFIG_ATM_ZATM),y)
 O_OBJS += zatm.o
 OX_OBJS += uPD98402.o
diff -u -r linux-2.4.0-test11.clean/drivers/atm/ambassador.c linux-2.4.0-test11.fs50+atmrefcount/drivers/atm/ambassador.c
--- linux-2.4.0-test11.clean/drivers/atm/ambassador.c	Wed Jul 12 12:25:48 2000
+++ linux-2.4.0-test11.fs50+atmrefcount/drivers/atm/ambassador.c	Wed Nov 22 08:59:12 2000
@@ -1251,15 +1251,10 @@
     }
   }
   
-  // prevent module unload while sleeping (kmalloc/down)
-  // doing this any earlier would complicate more error return paths
-  MOD_INC_USE_COUNT;
-  
   // get space for our vcc stuff
   vcc = kmalloc (sizeof(amb_vcc), GFP_KERNEL);
   if (!vcc) {
     PRINTK (KERN_ERR, "out of memory!");
-    MOD_DEC_USE_COUNT;
     return -ENOMEM;
   }
   atm_vcc->dev_data = (void *) vcc;
@@ -1425,7 +1420,6 @@
   // say the VPI/VCI is free again
   clear_bit(ATM_VF_ADDR,&atm_vcc->flags);
 
-  MOD_DEC_USE_COUNT;
   return;
 }
 
@@ -1703,7 +1697,8 @@
   close:	amb_close,
   send:		amb_send,
   sg_send:	amb_sg_send,
-  proc_read:	amb_proc_read
+  proc_read:	amb_proc_read,
+  owner:	THIS_MODULE,
 };
 
 /********** housekeeping **********/
diff -u -r linux-2.4.0-test11.clean/drivers/atm/atmdev_init.c linux-2.4.0-test11.fs50+atmrefcount/drivers/atm/atmdev_init.c
--- linux-2.4.0-test11.clean/drivers/atm/atmdev_init.c	Fri Apr 14 18:37:10 2000
+++ linux-2.4.0-test11.fs50+atmrefcount/drivers/atm/atmdev_init.c	Wed Nov 22 08:59:12 2000
@@ -54,7 +54,10 @@
 	devs += ia_detect();
 #endif
 #ifdef CONFIG_ATM_FORE200E
-        devs += fore200e_detect();
+	devs += fore200e_detect();
+#endif
+#ifdef CONFIG_ATM_FIRESTREAM
+	devs += fs_detect();
 #endif
 	return devs;
 }
diff -u -r linux-2.4.0-test11.clean/drivers/atm/atmtcp.c linux-2.4.0-test11.fs50+atmrefcount/drivers/atm/atmtcp.c
--- linux-2.4.0-test11.clean/drivers/atm/atmtcp.c	Wed Jul 12 12:24:48 2000
+++ linux-2.4.0-test11.fs50+atmrefcount/drivers/atm/atmtcp.c	Wed Nov 22 08:59:12 2000
@@ -109,7 +109,7 @@
 
 static void atmtcp_v_dev_close(struct atm_dev *dev)
 {
-	MOD_DEC_USE_COUNT;
+	/* Nothing.... Isn't this simple :-)  -- REW */
 }
 
 
@@ -297,7 +297,8 @@
 	close:		atmtcp_v_close,
 	ioctl:		atmtcp_v_ioctl,
 	send:		atmtcp_v_send,
-	proc_read:	atmtcp_v_proc
+	proc_read:	atmtcp_v_proc,
+	owner:		THIS_MODULE
 };
 
 
@@ -330,18 +331,13 @@
 	struct atmtcp_dev_data *dev_data;
 	struct atm_dev *dev;
 
-	MOD_INC_USE_COUNT;
-
 	dev_data = kmalloc(sizeof(*dev_data),GFP_KERNEL);
-	if (!dev_data) {
-		MOD_DEC_USE_COUNT;
+	if (!dev_data)
 		return -ENOMEM;
-	}
 
 	dev = atm_dev_register(DEV_LABEL,&atmtcp_v_dev_ops,itf,NULL);
 	if (!dev) {
 		kfree(dev_data);
-		MOD_DEC_USE_COUNT;
 		return itf == -1 ? -ENOMEM : -EBUSY;
 	}
 	dev->ci_range.vpi_bits = MAX_VPI_BITS;
diff -u -r linux-2.4.0-test11.clean/drivers/atm/fore200e.c linux-2.4.0-test11.fs50+atmrefcount/drivers/atm/fore200e.c
--- linux-2.4.0-test11.clean/drivers/atm/fore200e.c	Wed Nov  1 13:57:15 2000
+++ linux-2.4.0-test11.fs50+atmrefcount/drivers/atm/fore200e.c	Wed Nov 22 08:59:12 2000
@@ -1407,8 +1407,6 @@
     struct fore200e*     fore200e = FORE200E_DEV(vcc->dev);
     struct fore200e_vcc* fore200e_vcc;
     
-    MOD_INC_USE_COUNT;
-
     /* find a free VPI/VCI */
     fore200e_walk_vccs(vcc, &vpi, &vci);
 
@@ -1416,10 +1414,8 @@
     vcc->vci = vci;
 
     /* ressource checking only? */
-    if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) {
-    	MOD_DEC_USE_COUNT;
+    if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC)
 	return 0;
-    }
 
     set_bit(ATM_VF_ADDR, &vcc->flags);
     vcc->itf    = vcc->dev->number;
@@ -1437,7 +1433,6 @@
 	down(&fore200e->rate_sf);
 	if (fore200e->available_cell_rate < vcc->qos.txtp.max_pcr) {
 	    up(&fore200e->rate_sf);
-    	    MOD_DEC_USE_COUNT;
 	    return -EAGAIN;
 	}
 	/* reserving the pseudo-CBR bandwidth at this point grants us
@@ -1454,7 +1449,6 @@
 	down(&fore200e->rate_sf);
 	fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
 	up(&fore200e->rate_sf);
-    	MOD_DEC_USE_COUNT;
 	return -ENOMEM;
     }
 
@@ -1465,7 +1459,6 @@
 	down(&fore200e->rate_sf);
 	fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
 	up(&fore200e->rate_sf);
-    	MOD_DEC_USE_COUNT;
 	return -EBUSY;
     }
     
@@ -1498,10 +1491,6 @@
     
     fore200e_activate_vcin(fore200e, 0, vcc, 0);
     
-#ifdef MODULE
-    MOD_DEC_USE_COUNT;
-#endif
-	
     kfree(FORE200E_VCC(vcc));
 	
     if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) {
@@ -2599,8 +2588,6 @@
 
     printk(FORE200E "FORE Systems 200E-series driver - version " FORE200E_VERSION "\n");
 
-    MOD_INC_USE_COUNT;
-
     /* for each configured bus interface */
     for (link = 0, bus = fore200e_bus; bus->model_name; bus++) {
 
@@ -2626,9 +2613,6 @@
 	}
     }
 
-    if (link <= 0)
-	MOD_DEC_USE_COUNT;
-
     return link;
 }
 
@@ -2943,21 +2927,15 @@
 
 static const struct atmdev_ops fore200e_ops =
 {
-    NULL, /* fore200e_dev_close   */
-    fore200e_open,
-    fore200e_close,
-    fore200e_ioctl,
-    fore200e_getsockopt,
-    fore200e_setsockopt,
-    fore200e_send,
-    NULL, /* fore200e_sg_send,    */
-    NULL, /* fore200e_send_oam,   */
-    NULL, /* fore200e_phy_put,    */
-    NULL, /* fore200e_phy_get,    */
-    NULL, /* fore200e_feedback,   */
-    fore200e_change_qos,
-    NULL, /* fore200e_free_rx_skb */
-    fore200e_proc_read
+	open:         fore200e_open,
+	close:        fore200e_close,
+	ioctl:        fore200e_ioctl,
+	getsockopt:   fore200e_getsockopt,
+	setsockopt:   fore200e_setsockopt,
+	send:         fore200e_send,
+	change_qos:   fore200e_change_qos,
+	proc_read:    fore200e_proc_read,
+	owner:        THIS_MODULE,
 };
 
 
diff -u -r linux-2.4.0-test11.clean/drivers/atm/horizon.c linux-2.4.0-test11.fs50+atmrefcount/drivers/atm/horizon.c
--- linux-2.4.0-test11.clean/drivers/atm/horizon.c	Wed Jul 12 12:25:48 2000
+++ linux-2.4.0-test11.fs50+atmrefcount/drivers/atm/horizon.c	Wed Nov 22 08:59:12 2000
@@ -2491,15 +2491,10 @@
     return -EINVAL;
   }
   
-  // prevent module unload while sleeping (kmalloc)
-  // doing this any earlier would complicate more error return paths
-  MOD_INC_USE_COUNT;
-  
   // get space for our vcc stuff and copy parameters into it
   vccp = kmalloc (sizeof(hrz_vcc), GFP_KERNEL);
   if (!vccp) {
     PRINTK (KERN_ERR, "out of memory!");
-    MOD_DEC_USE_COUNT;
     return -ENOMEM;
   }
   *vccp = vcc;
@@ -2531,7 +2526,6 @@
   if (error) {
     PRINTD (DBG_QOS|DBG_VCC, "insufficient cell rate resources");
     kfree (vccp);
-    MOD_DEC_USE_COUNT;
     return error;
   }
   
@@ -2550,7 +2544,6 @@
       error = hrz_open_rx (dev, channel);
     if (error) {
       kfree (vccp);
-      MOD_DEC_USE_COUNT;
       return error;
     }
     // this link allows RX frames through
@@ -2620,7 +2613,6 @@
   kfree (vcc);
   // say the VPI/VCI is free again
   clear_bit(ATM_VF_ADDR,&atm_vcc->flags);
-  MOD_DEC_USE_COUNT;
 }
 
 #if 0
@@ -2751,7 +2743,8 @@
   close:	hrz_close,
   send:		hrz_send,
   sg_send:	hrz_sg_send,
-  proc_read:	hrz_proc_read
+  proc_read:	hrz_proc_read,
+  owner:	THIS_MODULE,
 };
 
 static int __init hrz_probe (void) {
diff -u -r linux-2.4.0-test11.clean/drivers/atm/iphase.c linux-2.4.0-test11.fs50+atmrefcount/drivers/atm/iphase.c
--- linux-2.4.0-test11.clean/drivers/atm/iphase.c	Mon Aug  7 07:20:09 2000
+++ linux-2.4.0-test11.fs50+atmrefcount/drivers/atm/iphase.c	Wed Nov 22 08:59:12 2000
@@ -3143,7 +3143,8 @@
 	phy_put:	ia_phy_put,  
 	phy_get:	ia_phy_get,  
 	change_qos:	ia_change_qos,  
-        proc_read:	ia_proc_read
+	proc_read:	ia_proc_read,
+	owner:		THIS_MODULE,
 };  
 	  
   
@@ -3219,7 +3220,6 @@
 		printk(KERN_ERR DEV_LABEL ": no adapter found\n");  
 		return -ENXIO;  
 	}  
-	// MOD_INC_USE_COUNT; 
    	ia_timer.expires = jiffies + 3*HZ;
    	add_timer(&ia_timer); 
    
@@ -3235,7 +3235,6 @@
         int i, j= 0;
  
 	IF_EVENT(printk(">ia cleanup_module\n");)  
-        // MOD_DEC_USE_COUNT;
 	if (MOD_IN_USE)  
 		printk("ia: module in use\n");  
         del_timer(&ia_timer);
diff -u -r linux-2.4.0-test11.clean/drivers/atm/nicstar.c linux-2.4.0-test11.fs50+atmrefcount/drivers/atm/nicstar.c
--- linux-2.4.0-test11.clean/drivers/atm/nicstar.c	Wed Nov  1 13:57:15 2000
+++ linux-2.4.0-test11.fs50+atmrefcount/drivers/atm/nicstar.c	Wed Nov 22 08:59:12 2000
@@ -268,7 +268,8 @@
    send:	ns_send,
    phy_put:	ns_phy_put,
    phy_get:	ns_phy_get,
-   proc_read:	ns_proc_read
+   proc_read:	ns_proc_read,
+   owner:	THIS_MODULE,
 };
 static struct timer_list ns_timer;
 static char *mac[NS_MAX_CARDS] = { NULL
@@ -1649,7 +1650,6 @@
    }
    
    set_bit(ATM_VF_READY,&vcc->flags);
-   MOD_INC_USE_COUNT;
    return 0;
 }
 
@@ -1778,7 +1778,6 @@
    vcc->dev_data = NULL;
    clear_bit(ATM_VF_PARTIAL,&vcc->flags);
    clear_bit(ATM_VF_ADDR,&vcc->flags);
-   MOD_DEC_USE_COUNT;
 
 #ifdef RX_DEBUG
    {
diff -u -r linux-2.4.0-test11.clean/drivers/pci/pci.ids linux-2.4.0-test11.fs50+atmrefcount/drivers/pci/pci.ids
--- linux-2.4.0-test11.clean/drivers/pci/pci.ids	Wed Nov  1 13:57:30 2000
+++ linux-2.4.0-test11.fs50+atmrefcount/drivers/pci/pci.ids	Wed Nov 22 08:59:13 2000
@@ -2438,7 +2438,9 @@
 	1221  82C092G
 119c  Information Technology Inst.
 119d  Bug, Inc. Sapporo Japan
-119e  Fujitsu Microelectronics Ltd.
+119e  Fujitsu Microelectronics Europe GMBH
+	0001 FireStream 155
+	0003 FireStream 50
 119f  Bull HN Information Systems
 11a0  Convex Computer Corporation
 11a1  Hamamatsu Photonics K.K.
diff -u -r linux-2.4.0-test11.clean/include/linux/atm_tcp.h linux-2.4.0-test11.fs50+atmrefcount/include/linux/atm_tcp.h
--- linux-2.4.0-test11.clean/include/linux/atm_tcp.h	Fri Oct 27 14:00:45 2000
+++ linux-2.4.0-test11.fs50+atmrefcount/include/linux/atm_tcp.h	Wed Nov 22 09:16:47 2000
@@ -65,6 +65,7 @@
 	int (*attach)(struct atm_vcc *vcc,int itf);
 	int (*create_persistent)(int itf);
 	int (*remove_persistent)(int itf);
+	struct module *owner;
 };
 
 extern struct atm_tcp_ops atm_tcp_ops;
diff -u -r linux-2.4.0-test11.clean/include/linux/atmdev.h linux-2.4.0-test11.fs50+atmrefcount/include/linux/atmdev.h
--- linux-2.4.0-test11.clean/include/linux/atmdev.h	Mon Nov 13 15:17:50 2000
+++ linux-2.4.0-test11.fs50+atmrefcount/include/linux/atmdev.h	Wed Nov 22 09:17:01 2000
@@ -375,6 +375,7 @@
 	void (*free_rx_skb)(struct atm_vcc *vcc, struct sk_buff *skb);
 		/* @@@ temporary hack */
 	int (*proc_read)(struct atm_dev *dev,loff_t *pos,char *page);
+	struct module *owner;
 };
 
 
diff -u -r linux-2.4.0-test11.clean/include/linux/pci_ids.h linux-2.4.0-test11.fs50+atmrefcount/include/linux/pci_ids.h
--- linux-2.4.0-test11.clean/include/linux/pci_ids.h	Wed Nov  1 13:57:45 2000
+++ linux-2.4.0-test11.fs50+atmrefcount/include/linux/pci_ids.h	Wed Nov 22 08:59:13 2000
@@ -871,6 +871,10 @@
 #define PCI_VENDOR_ID_OMEGA		0x119b
 #define PCI_DEVICE_ID_OMEGA_82C092G	0x1221
 
+#define PCI_VENDOR_ID_FUJITSU_ME	0x119e
+#define PCI_DEVICE_ID_FUJITSU_FS155	0x0001
+#define PCI_DEVICE_ID_FUJITSU_FS50	0x0003
+
 #define PCI_SUBVENDOR_ID_KEYSPAN	0x11a9
 #define PCI_SUBDEVICE_ID_KEYSPAN_SX2	0x5334
 
diff -u -r linux-2.4.0-test11.clean/net/atm/addr.c linux-2.4.0-test11.fs50+atmrefcount/net/atm/addr.c
--- linux-2.4.0-test11.clean/net/atm/addr.c	Wed Mar 22 08:38:26 2000
+++ linux-2.4.0-test11.fs50+atmrefcount/net/atm/addr.c	Wed Nov 22 08:59:13 2000
@@ -42,7 +42,7 @@
  */
 
 static DECLARE_MUTEX(local_lock);
-
+extern  spinlock_t atm_dev_lock;
 
 static void notify_sigd(struct atm_dev *dev)
 {
@@ -58,12 +58,14 @@
 	struct atm_dev_addr *this;
 
 	down(&local_lock);
+	spin_lock (&atm_dev_lock);		
 	while (dev->local) {
 		this = dev->local;
 		dev->local = this->next;
 		kfree(this);
 	}
 	up(&local_lock);
+	spin_unlock (&atm_dev_lock);
 	notify_sigd(dev);
 }
 
diff -u -r linux-2.4.0-test11.clean/net/atm/common.c linux-2.4.0-test11.fs50+atmrefcount/net/atm/common.c
--- linux-2.4.0-test11.clean/net/atm/common.c	Wed Jul 12 12:26:08 2000
+++ linux-2.4.0-test11.fs50+atmrefcount/net/atm/common.c	Wed Nov 22 08:59:13 2000
@@ -72,6 +72,7 @@
 #define DPRINTK(format,args...)
 #endif
 
+spinlock_t atm_dev_lock = SPIN_LOCK_UNLOCKED;
 
 static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
 {
@@ -139,13 +140,19 @@
 				vcc->dev->ops->free_rx_skb(vcc,skb);
 			else kfree_skb(skb);
 		}
+		spin_lock (&atm_dev_lock);	
+		fops_put (vcc->dev->ops);
 		if (atomic_read(&vcc->rx_inuse))
 			printk(KERN_WARNING "atm_release_vcc: strange ... "
 			    "rx_inuse == %d after closing\n",
 			    atomic_read(&vcc->rx_inuse));
 		bind_vcc(vcc,NULL);
-	}
+	} else
+		spin_lock (&atm_dev_lock);	
+
 	if (free_sk) free_atm_vcc_sk(sk);
+
+	spin_unlock (&atm_dev_lock);
 }
 
 
@@ -238,9 +245,11 @@
 	    vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu);
 	DPRINTK("  RX: %d, PCR %d..%d, SDU %d\n",vcc->qos.rxtp.traffic_class,
 	    vcc->qos.rxtp.min_pcr,vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu);
+	fops_get (dev->ops);
 	if (dev->ops->open) {
 		error = dev->ops->open(vcc,vpi,vci);
 		if (error) {
+			fops_put (dev->ops);
 			bind_vcc(vcc,NULL);
 			return error;
 		}
@@ -252,10 +261,18 @@
 static int atm_do_connect(struct atm_vcc *vcc,int itf,int vpi,int vci)
 {
 	struct atm_dev *dev;
+	int return_val;
 
+	spin_lock (&atm_dev_lock);
 	dev = atm_find_dev(itf);
-	if (!dev) return -ENODEV;
-	return atm_do_connect_dev(vcc,dev,vpi,vci);
+	if (!dev)
+		return_val =  -ENODEV;
+	else
+		return_val = atm_do_connect_dev(vcc,dev,vpi,vci);
+
+	spin_unlock (&atm_dev_lock);
+
+	return return_val;
 }
 
 
@@ -285,8 +302,10 @@
 	else {
 		struct atm_dev *dev;
 
+		spin_lock (&atm_dev_lock);
 		for (dev = atm_devs; dev; dev = dev->next)
 			if (!atm_do_connect_dev(vcc,dev,vpi,vci)) break;
+		spin_unlock (&atm_dev_lock);
 		if (!dev) return -ENODEV;
 	}
 	if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
@@ -523,57 +542,86 @@
 	struct atm_vcc *vcc;
 	int *tmp_buf;
 	void *buf;
-	int error,len,size,number;
+	int error,len,size,number, ret_val;
 
+	ret_val = 0;
+	spin_lock (&atm_dev_lock);
 	vcc = ATM_SD(sock);
 	switch (cmd) {
 		case SIOCOUTQ:
 			if (sock->state != SS_CONNECTED ||
-			    !test_bit(ATM_VF_READY,&vcc->flags))
-				return -EINVAL;
-			return put_user(vcc->sk->sndbuf-
+			    !test_bit(ATM_VF_READY,&vcc->flags)) {
+				ret_val =  -EINVAL;
+				goto done;
+			}
+			ret_val =  put_user(vcc->sk->sndbuf-
 			    atomic_read(&vcc->tx_inuse)-ATM_PDU_OVHD,
 			    (int *) arg) ? -EFAULT : 0;
+			goto done;
 		case SIOCINQ:
 			{
 				struct sk_buff *skb;
 
-				if (sock->state != SS_CONNECTED)
-					return -EINVAL;
+				if (sock->state != SS_CONNECTED) {
+					ret_val = -EINVAL;
+					goto done;
+				}
 				skb = skb_peek(&vcc->recvq);
-				return put_user(skb ? skb->len : 0,(int *) arg)
+				ret_val = put_user(skb ? skb->len : 0,(int *) arg)
 				    ? -EFAULT : 0;
+				goto done;
 			}
 		case ATM_GETNAMES:
 			if (get_user(buf,
-			    &((struct atm_iobuf *) arg)->buffer))
-				return -EFAULT;
+				     &((struct atm_iobuf *) arg)->buffer)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			if (get_user(len,
-			    &((struct atm_iobuf *) arg)->length))
-				return -EFAULT;
+				     &((struct atm_iobuf *) arg)->length)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			size = 0;
 			for (dev = atm_devs; dev; dev = dev->next)
 				size += sizeof(int);
-			if (size > len) return -E2BIG;
+			if (size > len) {
+				ret_val = -E2BIG;
+				goto done;
+			}
 			tmp_buf = kmalloc(size,GFP_KERNEL);
-			if (!tmp_buf) return -ENOMEM;
+			if (!tmp_buf) {
+				ret_val = -ENOMEM;
+				goto done;
+			}
 			for (dev = atm_devs; dev; dev = dev->next)
 				*tmp_buf++ = dev->number;
-			if (copy_to_user(buf,(char *) tmp_buf-size,size))
-				return -EFAULT;
-			return put_user(size,
+			if (copy_to_user(buf,(char *) tmp_buf-size,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
+		        ret_val = put_user(size,
 			    &((struct atm_iobuf *) arg)->length) ? -EFAULT : 0;
+			goto done;
 		case SIOCGSTAMP: /* borrowed from IP */
-			if (!vcc->timestamp.tv_sec) return -ENOENT;
+			if (!vcc->timestamp.tv_sec) {
+				ret_val = -ENOENT;
+				goto done;
+			}
 			vcc->timestamp.tv_sec += vcc->timestamp.tv_usec/1000000;
 			vcc->timestamp.tv_usec %= 1000000;
-			return copy_to_user((void *) arg,&vcc->timestamp,
+			ret_val = copy_to_user((void *) arg,&vcc->timestamp,
 			    sizeof(struct timeval)) ? -EFAULT : 0;
+			goto done;
 		case ATM_SETSC:
 			printk(KERN_WARNING "ATM_SETSC is obsolete\n");
-			return 0;
+			ret_val = 0;
+			goto done;
 		case ATMSIGD_CTRL:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			/*
 			 * The user/kernel protocol for exchanging signalling
 			 * info uses kernel pointers as opaque references,
@@ -581,175 +629,308 @@
 			 * on the kernel... so we should make sure that we
 			 * have the same privledges that /proc/kcore needs
 			 */
-			if (!capable(CAP_SYS_RAWIO)) return -EPERM;
+			if (!capable(CAP_SYS_RAWIO)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			error = sigd_attach(vcc);
 			if (!error) sock->state = SS_CONNECTED;
-			return error;
+			ret_val = error;
+			goto done;
 #ifdef CONFIG_ATM_CLIP
 		case SIOCMKCLIP:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return clip_create(arg);
+			if (!capable(CAP_NET_ADMIN))
+				ret_val = -EPERM;
+			else 
+				ret_val = clip_create(arg);
+			goto done;
 		case ATMARPD_CTRL:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			error = atm_init_atmarp(vcc);
 			if (!error) sock->state = SS_CONNECTED;
-			return error;
+			ret_val = error;
+			goto done;
 		case ATMARP_MKIP:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return clip_mkip(vcc,arg);
+			if (!capable(CAP_NET_ADMIN)) 
+				ret_val = -EPERM;
+			else 
+				ret_val = clip_mkip(vcc,arg);
+			goto done;
 		case ATMARP_SETENTRY:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return clip_setentry(vcc,arg);
+			if (!capable(CAP_NET_ADMIN)) 
+				ret_val = -EPERM;
+			else
+				ret_val = clip_setentry(vcc,arg);
+			goto done;
 		case ATMARP_ENCAP:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return clip_encap(vcc,arg);
+			if (!capable(CAP_NET_ADMIN)) 
+				ret_val = -EPERM;
+			else
+				ret_val = clip_encap(vcc,arg);
+			goto done;
 #endif
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
                 case ATMLEC_CTRL:
-                        if (!capable(CAP_NET_ADMIN)) return -EPERM;
+                        if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
                         if (atm_lane_ops.lecd_attach == NULL)
                                 atm_lane_init();
-                        if (atm_lane_ops.lecd_attach == NULL) /* try again */
-                                return -ENOSYS;
-                        error = atm_lane_ops.lecd_attach(vcc, (int)arg);
-                        if (error >= 0) sock->state = SS_CONNECTED;
-                        return error;
+                        if (atm_lane_ops.lecd_attach == NULL) { /* try again */
+				ret_val = -ENOSYS;
+				goto done;
+			}
+			error = atm_lane_ops.lecd_attach(vcc, (int)arg);
+			if (error >= 0) sock->state = SS_CONNECTED;
+			ret_val =  error;
+			goto done;
                 case ATMLEC_MCAST:
-                        if (!capable(CAP_NET_ADMIN)) return -EPERM;
-                        return atm_lane_ops.mcast_attach(vcc, (int)arg);
+			if (!capable(CAP_NET_ADMIN))
+				ret_val = -EPERM;
+			else
+				ret_val = atm_lane_ops.mcast_attach(vcc, (int)arg);
+			goto done;
                 case ATMLEC_DATA:
-                        if (!capable(CAP_NET_ADMIN)) return -EPERM;
-                        return atm_lane_ops.vcc_attach(vcc, (void*)arg);
+			if (!capable(CAP_NET_ADMIN))
+				ret_val = -EPERM;
+			else
+				ret_val = atm_lane_ops.vcc_attach(vcc, (void*)arg);
+			goto done;
 #endif
 #if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE)
 		case ATMMPC_CTRL:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-                        if (atm_mpoa_ops.mpoad_attach == NULL)
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
+			if (atm_mpoa_ops.mpoad_attach == NULL)
                                 atm_mpoa_init();
-                        if (atm_mpoa_ops.mpoad_attach == NULL) /* try again */
-                                return -ENOSYS;
-                        error = atm_mpoa_ops.mpoad_attach(vcc, (int)arg);
-                        if (error >= 0) sock->state = SS_CONNECTED;
-                        return error;
+			if (atm_mpoa_ops.mpoad_attach == NULL) { /* try again */
+				ret_val = -ENOSYS;
+				goto done;
+			}
+			error = atm_mpoa_ops.mpoad_attach(vcc, (int)arg);
+			if (error >= 0) sock->state = SS_CONNECTED;
+			ret_val = error;
+			goto done;
 		case ATMMPC_DATA:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return atm_mpoa_ops.vcc_attach(vcc, arg);
+			if (!capable(CAP_NET_ADMIN)) 
+				ret_val = -EPERM;
+			else
+				ret_val = atm_mpoa_ops.vcc_attach(vcc, arg);
+			goto done;
 #endif
 #if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE)
 		case SIOCSIFATMTCP:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			if (!atm_tcp_ops.attach) return -ENOPKG;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
+			if (!atm_tcp_ops.attach) {
+				ret_val = -ENOPKG;
+				goto done;
+			}
+			fops_get (&atm_tcp_ops);
 			error = atm_tcp_ops.attach(vcc,(int) arg);
 			if (error >= 0) sock->state = SS_CONNECTED;
-			return error;
+			else            fops_put (&atm_tcp_ops);
+			ret_val = error;
+			goto done;
 		case ATMTCP_CREATE:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			if (!atm_tcp_ops.create_persistent) return -ENOPKG;
-			return atm_tcp_ops.create_persistent((int) arg);
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
+			if (!atm_tcp_ops.create_persistent) {
+				ret_val = -ENOPKG;
+				goto done;
+			}
+			error = atm_tcp_ops.create_persistent((int) arg);
+			if (error < 0) fops_put (&atm_tcp_ops);
+			ret_val = error;
+			goto done;
 		case ATMTCP_REMOVE:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			if (!atm_tcp_ops.remove_persistent) return -ENOPKG;
-			return atm_tcp_ops.remove_persistent((int) arg);
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
+			if (!atm_tcp_ops.remove_persistent) {
+				ret_val = -ENOPKG;
+				goto done;
+			}
+			error = atm_tcp_ops.remove_persistent((int) arg);
+			fops_put (&atm_tcp_ops);
+			ret_val = error;
+			goto done;
 #endif
 		default:
 			break;
 	}
-	if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) return -EFAULT;
-	if (get_user(len,&((struct atmif_sioc *) arg)->length)) return -EFAULT;
-	if (get_user(number,&((struct atmif_sioc *) arg)->number))
-		return -EFAULT;
-	if (!(dev = atm_find_dev(number))) return -ENODEV;
+	if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) {
+		ret_val = -EFAULT;
+		goto done;
+	}
+	if (get_user(len,&((struct atmif_sioc *) arg)->length)) {
+		ret_val = -EFAULT;
+		goto done;
+	}
+	if (get_user(number,&((struct atmif_sioc *) arg)->number)) {
+		ret_val = -EFAULT;
+		goto done;
+	}
+	if (!(dev = atm_find_dev(number))) {
+		ret_val = -ENODEV;
+		goto done;
+	}
+	
 	size = 0;
 	switch (cmd) {
 		case ATM_GETTYPE:
 			size = strlen(dev->type)+1;
-			if (copy_to_user(buf,dev->type,size)) return -EFAULT;
+			if (copy_to_user(buf,dev->type,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			break;
 		case ATM_GETESI:
 			size = ESI_LEN;
-			if (copy_to_user(buf,dev->esi,size)) return -EFAULT;
+			if (copy_to_user(buf,dev->esi,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			break;
 		case ATM_SETESI:
 			{
 				int i;
 
 				for (i = 0; i < ESI_LEN; i++)
-					if (dev->esi[i]) return -EEXIST;
+					if (dev->esi[i]) {
+						ret_val = -EEXIST;
+						goto done;
+					}
 			}
 			/* fall through */
 		case ATM_SETESIF:
 			{
 				unsigned char esi[ESI_LEN];
 
-				if (!capable(CAP_NET_ADMIN)) return -EPERM;
-				if (copy_from_user(esi,buf,ESI_LEN))
-					return -EFAULT;
+				if (!capable(CAP_NET_ADMIN)) {
+					ret_val = -EPERM;
+					goto done;
+				}
+				if (copy_from_user(esi,buf,ESI_LEN)) {
+					ret_val = -EFAULT;
+					goto done;
+				}
 				memcpy(dev->esi,esi,ESI_LEN);
-				return ESI_LEN;
+				ret_val =  ESI_LEN;
+				goto done;
 			}
 		case ATM_GETSTATZ:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			/* fall through */
 		case ATM_GETSTAT:
 			size = sizeof(struct atm_dev_stats);
 			error = fetch_stats(dev,buf,cmd == ATM_GETSTATZ);
-			if (error) return error;
+			if (error) {
+				ret_val = error;
+				goto done;
+			}
 			break;
 		case ATM_GETCIRANGE:
 			size = sizeof(struct atm_cirange);
-			if (copy_to_user(buf,&dev->ci_range,size))
-				return -EFAULT;
+			if (copy_to_user(buf,&dev->ci_range,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			break;
 		case ATM_GETLINKRATE:
 			size = sizeof(int);
-			if (copy_to_user(buf,&dev->link_rate,size))
-				return -EFAULT;
+			if (copy_to_user(buf,&dev->link_rate,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			break;
 		case ATM_RSTADDR:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			reset_addr(dev);
 			break;
 		case ATM_ADDADDR:
 		case ATM_DELADDR:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			{
 				struct sockaddr_atmsvc addr;
 
-				if (copy_from_user(&addr,buf,sizeof(addr)))
-					return -EFAULT;
+				if (copy_from_user(&addr,buf,sizeof(addr))) {
+					ret_val = -EFAULT;
+					goto done;
+				}
 				if (cmd == ATM_ADDADDR)
-					return add_addr(dev,&addr);
-				else return del_addr(dev,&addr);
+					ret_val = add_addr(dev,&addr);
+				else
+					ret_val = del_addr(dev,&addr);
+				goto done;
 			}
 		case ATM_GETADDR:
 			size = get_addr(dev,buf,len);
-			if (size < 0) return size;
+			if (size < 0)
+				ret_val = size;
+			else
 			/* may return 0, but later on size == 0 means "don't
 			   write the length" */
-			return put_user(size,
-			    &((struct atmif_sioc *) arg)->length) ? -EFAULT : 0;
+				ret_val = put_user(size,
+						   &((struct atmif_sioc *) arg)->length) ? -EFAULT : 0;
+			goto done;
 		case ATM_SETLOOP:
 			if (__ATM_LM_XTRMT((int) (long) buf) &&
 			    __ATM_LM_XTLOC((int) (long) buf) >
-			    __ATM_LM_XTRMT((int) (long) buf))
-				return -EINVAL;
+			    __ATM_LM_XTRMT((int) (long) buf)) {
+				ret_val = -EINVAL;
+				goto done;
+			}
 			/* fall through */
 		case ATM_SETCIRANGE:
 		case SONET_GETSTATZ:
 		case SONET_SETDIAG:
 		case SONET_CLRDIAG:
 		case SONET_SETFRAMING:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			/* fall through */
 		default:
-			if (!dev->ops->ioctl) return -EINVAL;
+			if (!dev->ops->ioctl) {
+				ret_val = -EINVAL;
+				goto done;
+			}
 			size = dev->ops->ioctl(dev,cmd,buf);
-			if (size < 0)
-				return size == -ENOIOCTLCMD ? -EINVAL : size;
+			if (size < 0) {
+				ret_val = (size == -ENOIOCTLCMD ? -EINVAL : size);
+				goto done;
+			}
 	}
-	if (!size) return 0;
-	return put_user(size,&((struct atmif_sioc *) arg)->length) ?
-	    -EFAULT : 0;
+	
+	if (size)
+		ret_val =  put_user(size,&((struct atmif_sioc *) arg)->length) ?
+			-EFAULT : 0;
+
+ done:
+	spin_unlock (&atm_dev_lock); 
+	return ret_val;
 }
 
 
diff -u -r linux-2.4.0-test11.clean/net/atm/resources.c linux-2.4.0-test11.fs50+atmrefcount/net/atm/resources.c
--- linux-2.4.0-test11.clean/net/atm/resources.c	Thu Oct 19 13:53:13 2000
+++ linux-2.4.0-test11.fs50+atmrefcount/net/atm/resources.c	Wed Nov 22 09:08:51 2000
@@ -25,6 +25,7 @@
 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;
 
 static spinlock_t atm_dev_lock = SPIN_LOCK_UNLOCKED;
 
@@ -38,7 +39,6 @@
 	memset(dev,0,sizeof(*dev));
 	dev->type = type;
 
-	printk ("spin_lock alloc_atm_dev\n");
 	spin_lock (&atm_dev_lock);
 
 	dev->prev = last_dev;
@@ -52,7 +52,6 @@
 	
 
 	last_dev = dev;
-	printk ("spin_unlock alloc_atm_dev\n");
 	spin_unlock (&atm_dev_lock);
 
 	return dev;
@@ -61,11 +60,15 @@
 
 static void free_atm_dev(struct atm_dev *dev)
 {
+	spin_lock (&atm_dev_lock);
+	
 	if (dev->prev) dev->prev->next = dev->next;
 	else atm_devs = dev->next;
 	if (dev->next) dev->next->prev = dev->prev;
 	else last_dev = dev->prev;
 	kfree(dev);
+	
+	spin_unlock (&atm_dev_lock);
 }
 
 
@@ -91,16 +94,13 @@
 		return NULL;
 	}
 	if (number != -1) {
-		printk ("spin_lock alloc_atm_dev\n");
 		spin_lock (&atm_dev_lock);
 		if (atm_find_dev(number)) {
 			free_atm_dev(dev);
-			printk ("spin_unlock alloc_atm_dev\n");
 			spin_unlock (&atm_dev_lock);
 			return NULL;
 		}
 		dev->number = number;
-		printk ("spin_unlock alloc_atm_dev\n");
 		spin_unlock (&atm_dev_lock);		
 	}
 	else {
@@ -119,10 +119,12 @@
 		if (atm_proc_dev_register(dev) < 0) {
 			printk(KERN_ERR "atm_dev_register: "
 			    "atm_proc_dev_register failed for dev %s\n",type);
+			spin_unlock (&atm_dev_lock);		
 			free_atm_dev(dev);
 			return NULL;
 		}
 #endif
+	spin_unlock (&atm_dev_lock);		
 	return dev;
 }
 
diff -u -r linux-2.4.0-test11.clean/net/atm/signaling.c linux-2.4.0-test11.fs50+atmrefcount/net/atm/signaling.c
--- linux-2.4.0-test11.clean/net/atm/signaling.c	Wed Aug  2 10:27:14 2000
+++ linux-2.4.0-test11.fs50+atmrefcount/net/atm/signaling.c	Wed Nov 22 08:59:13 2000
@@ -33,6 +33,7 @@
 struct atm_vcc *sigd = NULL;
 static DECLARE_WAIT_QUEUE_HEAD(sigd_sleep);
 
+extern spinlock_t atm_dev_lock;
 
 static void sigd_put_skb(struct sk_buff *skb)
 {
@@ -218,7 +219,10 @@
 		printk(KERN_ERR "sigd_close: closing with requests pending\n");
 	while ((skb = skb_dequeue(&vcc->recvq))) kfree_skb(skb);
 	purge_vccs(nodev_vccs);
+
+	spin_lock (&atm_dev_lock);
 	for (dev = atm_devs; dev; dev = dev->next) purge_vccs(dev->vccs);
+	spin_unlock (&atm_dev_lock);
 }
 
 


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] atmrefcount
  2000-11-22  9:31 [PATCH] atmrefcount Patrick van de Lageweg
@ 2000-11-22 16:03 ` Mitchell Blank Jr
  0 siblings, 0 replies; 6+ messages in thread
From: Mitchell Blank Jr @ 2000-11-22 16:03 UTC (permalink / raw)
  To: Patrick van de Lageweg
  Cc: Linus Torvalds, Linux Kernel Mailing List, Rogier Wolff

Patrick van de Lageweg wrote:
> This patch contains the fix for the atmrefcount problem (noted as a
> critical problem in Ted's todo list). It also has the makefile
> modifications for the firestream driver in a separate email. 

Could you please split the two patches so that they're actually independant
(i.e. put all the stuff for the new driver in its own patch).  I'll
comment on that driver seperately.

-Mitch
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH] atmrefcount
@ 2000-11-29  8:57 Patrick van de Lageweg
  0 siblings, 0 replies; 6+ messages in thread
From: Patrick van de Lageweg @ 2000-11-29  8:57 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Rogier Wolff, Linux Kernel Mailing List, Alan Cox

Hi Linus,

This patch contains the fix for the atmrefcount problem (noted as a
critical problem in Ted's todo list).

	Patrick

diff -u -r linux-2.4.0-test11.clean/drivers/atm/ambassador.c linux-2.4.0-test11.atmrefcount/drivers/atm/ambassador.c
--- linux-2.4.0-test11.clean/drivers/atm/ambassador.c	Fri Jul  7 06:37:24 2000
+++ linux-2.4.0-test11.atmrefcount/drivers/atm/ambassador.c	Wed Nov 29 08:41:21 2000
@@ -1251,15 +1251,10 @@
     }
   }
   
-  // prevent module unload while sleeping (kmalloc/down)
-  // doing this any earlier would complicate more error return paths
-  MOD_INC_USE_COUNT;
-  
   // get space for our vcc stuff
   vcc = kmalloc (sizeof(amb_vcc), GFP_KERNEL);
   if (!vcc) {
     PRINTK (KERN_ERR, "out of memory!");
-    MOD_DEC_USE_COUNT;
     return -ENOMEM;
   }
   atm_vcc->dev_data = (void *) vcc;
@@ -1425,7 +1420,6 @@
   // say the VPI/VCI is free again
   clear_bit(ATM_VF_ADDR,&atm_vcc->flags);
 
-  MOD_DEC_USE_COUNT;
   return;
 }
 
@@ -1703,7 +1697,8 @@
   close:	amb_close,
   send:		amb_send,
   sg_send:	amb_sg_send,
-  proc_read:	amb_proc_read
+  proc_read:	amb_proc_read,
+  owner:	THIS_MODULE,
 };
 
 /********** housekeeping **********/
diff -u -r linux-2.4.0-test11.clean/drivers/atm/atmdev_init.c linux-2.4.0-test11.atmrefcount/drivers/atm/atmdev_init.c
--- linux-2.4.0-test11.clean/drivers/atm/atmdev_init.c	Fri Apr 14 18:37:10 2000
+++ linux-2.4.0-test11.atmrefcount/drivers/atm/atmdev_init.c	Wed Nov 29 08:41:21 2000
@@ -54,7 +54,7 @@
 	devs += ia_detect();
 #endif
 #ifdef CONFIG_ATM_FORE200E
-        devs += fore200e_detect();
+	devs += fore200e_detect();
 #endif
 	return devs;
 }
diff -u -r linux-2.4.0-test11.clean/drivers/atm/atmtcp.c linux-2.4.0-test11.atmrefcount/drivers/atm/atmtcp.c
--- linux-2.4.0-test11.clean/drivers/atm/atmtcp.c	Wed Nov 15 08:36:01 2000
+++ linux-2.4.0-test11.atmrefcount/drivers/atm/atmtcp.c	Wed Nov 29 08:41:21 2000
@@ -110,7 +110,7 @@
 
 static void atmtcp_v_dev_close(struct atm_dev *dev)
 {
-	MOD_DEC_USE_COUNT;
+	/* Nothing.... Isn't this simple :-)  -- REW */
 }
 
 
@@ -298,7 +298,8 @@
 	close:		atmtcp_v_close,
 	ioctl:		atmtcp_v_ioctl,
 	send:		atmtcp_v_send,
-	proc_read:	atmtcp_v_proc
+	proc_read:	atmtcp_v_proc,
+	owner:		THIS_MODULE
 };
 
 
@@ -331,18 +332,13 @@
 	struct atmtcp_dev_data *dev_data;
 	struct atm_dev *dev;
 
-	MOD_INC_USE_COUNT;
-
 	dev_data = kmalloc(sizeof(*dev_data),GFP_KERNEL);
-	if (!dev_data) {
-		MOD_DEC_USE_COUNT;
+	if (!dev_data)
 		return -ENOMEM;
-	}
 
 	dev = atm_dev_register(DEV_LABEL,&atmtcp_v_dev_ops,itf,NULL);
 	if (!dev) {
 		kfree(dev_data);
-		MOD_DEC_USE_COUNT;
 		return itf == -1 ? -ENOMEM : -EBUSY;
 	}
 	dev->ci_range.vpi_bits = MAX_VPI_BITS;
diff -u -r linux-2.4.0-test11.clean/drivers/atm/fore200e.c linux-2.4.0-test11.atmrefcount/drivers/atm/fore200e.c
--- linux-2.4.0-test11.clean/drivers/atm/fore200e.c	Mon Oct 16 21:56:50 2000
+++ linux-2.4.0-test11.atmrefcount/drivers/atm/fore200e.c	Wed Nov 29 08:41:21 2000
@@ -1407,8 +1407,6 @@
     struct fore200e*     fore200e = FORE200E_DEV(vcc->dev);
     struct fore200e_vcc* fore200e_vcc;
     
-    MOD_INC_USE_COUNT;
-
     /* find a free VPI/VCI */
     fore200e_walk_vccs(vcc, &vpi, &vci);
 
@@ -1416,10 +1414,8 @@
     vcc->vci = vci;
 
     /* ressource checking only? */
-    if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) {
-    	MOD_DEC_USE_COUNT;
+    if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC)
 	return 0;
-    }
 
     set_bit(ATM_VF_ADDR, &vcc->flags);
     vcc->itf    = vcc->dev->number;
@@ -1437,7 +1433,6 @@
 	down(&fore200e->rate_sf);
 	if (fore200e->available_cell_rate < vcc->qos.txtp.max_pcr) {
 	    up(&fore200e->rate_sf);
-    	    MOD_DEC_USE_COUNT;
 	    return -EAGAIN;
 	}
 	/* reserving the pseudo-CBR bandwidth at this point grants us
@@ -1454,7 +1449,6 @@
 	down(&fore200e->rate_sf);
 	fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
 	up(&fore200e->rate_sf);
-    	MOD_DEC_USE_COUNT;
 	return -ENOMEM;
     }
 
@@ -1465,7 +1459,6 @@
 	down(&fore200e->rate_sf);
 	fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
 	up(&fore200e->rate_sf);
-    	MOD_DEC_USE_COUNT;
 	return -EBUSY;
     }
     
@@ -1498,10 +1491,6 @@
     
     fore200e_activate_vcin(fore200e, 0, vcc, 0);
     
-#ifdef MODULE
-    MOD_DEC_USE_COUNT;
-#endif
-	
     kfree(FORE200E_VCC(vcc));
 	
     if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) {
@@ -2599,8 +2588,6 @@
 
     printk(FORE200E "FORE Systems 200E-series driver - version " FORE200E_VERSION "\n");
 
-    MOD_INC_USE_COUNT;
-
     /* for each configured bus interface */
     for (link = 0, bus = fore200e_bus; bus->model_name; bus++) {
 
@@ -2626,9 +2613,6 @@
 	}
     }
 
-    if (link <= 0)
-	MOD_DEC_USE_COUNT;
-
     return link;
 }
 
@@ -2943,21 +2927,15 @@
 
 static const struct atmdev_ops fore200e_ops =
 {
-    NULL, /* fore200e_dev_close   */
-    fore200e_open,
-    fore200e_close,
-    fore200e_ioctl,
-    fore200e_getsockopt,
-    fore200e_setsockopt,
-    fore200e_send,
-    NULL, /* fore200e_sg_send,    */
-    NULL, /* fore200e_send_oam,   */
-    NULL, /* fore200e_phy_put,    */
-    NULL, /* fore200e_phy_get,    */
-    NULL, /* fore200e_feedback,   */
-    fore200e_change_qos,
-    NULL, /* fore200e_free_rx_skb */
-    fore200e_proc_read
+	open:         fore200e_open,
+	close:        fore200e_close,
+	ioctl:        fore200e_ioctl,
+	getsockopt:   fore200e_getsockopt,
+	setsockopt:   fore200e_setsockopt,
+	send:         fore200e_send,
+	change_qos:   fore200e_change_qos,
+	proc_read:    fore200e_proc_read,
+	owner:        THIS_MODULE,
 };
 
 
diff -u -r linux-2.4.0-test11.clean/drivers/atm/horizon.c linux-2.4.0-test11.atmrefcount/drivers/atm/horizon.c
--- linux-2.4.0-test11.clean/drivers/atm/horizon.c	Fri Jul  7 06:37:24 2000
+++ linux-2.4.0-test11.atmrefcount/drivers/atm/horizon.c	Wed Nov 29 08:41:22 2000
@@ -2491,15 +2491,10 @@
     return -EINVAL;
   }
   
-  // prevent module unload while sleeping (kmalloc)
-  // doing this any earlier would complicate more error return paths
-  MOD_INC_USE_COUNT;
-  
   // get space for our vcc stuff and copy parameters into it
   vccp = kmalloc (sizeof(hrz_vcc), GFP_KERNEL);
   if (!vccp) {
     PRINTK (KERN_ERR, "out of memory!");
-    MOD_DEC_USE_COUNT;
     return -ENOMEM;
   }
   *vccp = vcc;
@@ -2531,7 +2526,6 @@
   if (error) {
     PRINTD (DBG_QOS|DBG_VCC, "insufficient cell rate resources");
     kfree (vccp);
-    MOD_DEC_USE_COUNT;
     return error;
   }
   
@@ -2550,7 +2544,6 @@
       error = hrz_open_rx (dev, channel);
     if (error) {
       kfree (vccp);
-      MOD_DEC_USE_COUNT;
       return error;
     }
     // this link allows RX frames through
@@ -2620,7 +2613,6 @@
   kfree (vcc);
   // say the VPI/VCI is free again
   clear_bit(ATM_VF_ADDR,&atm_vcc->flags);
-  MOD_DEC_USE_COUNT;
 }
 
 #if 0
@@ -2751,7 +2743,8 @@
   close:	hrz_close,
   send:		hrz_send,
   sg_send:	hrz_sg_send,
-  proc_read:	hrz_proc_read
+  proc_read:	hrz_proc_read,
+  owner:	THIS_MODULE,
 };
 
 static int __init hrz_probe (void) {
diff -u -r linux-2.4.0-test11.clean/drivers/atm/iphase.c linux-2.4.0-test11.atmrefcount/drivers/atm/iphase.c
--- linux-2.4.0-test11.clean/drivers/atm/iphase.c	Mon Aug  7 07:20:09 2000
+++ linux-2.4.0-test11.atmrefcount/drivers/atm/iphase.c	Wed Nov 29 08:41:22 2000
@@ -3143,7 +3143,8 @@
 	phy_put:	ia_phy_put,  
 	phy_get:	ia_phy_get,  
 	change_qos:	ia_change_qos,  
-        proc_read:	ia_proc_read
+	proc_read:	ia_proc_read,
+	owner:		THIS_MODULE,
 };  
 	  
   
@@ -3219,7 +3220,6 @@
 		printk(KERN_ERR DEV_LABEL ": no adapter found\n");  
 		return -ENXIO;  
 	}  
-	// MOD_INC_USE_COUNT; 
    	ia_timer.expires = jiffies + 3*HZ;
    	add_timer(&ia_timer); 
    
@@ -3235,7 +3235,6 @@
         int i, j= 0;
  
 	IF_EVENT(printk(">ia cleanup_module\n");)  
-        // MOD_DEC_USE_COUNT;
 	if (MOD_IN_USE)  
 		printk("ia: module in use\n");  
         del_timer(&ia_timer);
diff -u -r linux-2.4.0-test11.clean/drivers/atm/nicstar.c linux-2.4.0-test11.atmrefcount/drivers/atm/nicstar.c
--- linux-2.4.0-test11.clean/drivers/atm/nicstar.c	Tue Nov 14 22:16:33 2000
+++ linux-2.4.0-test11.atmrefcount/drivers/atm/nicstar.c	Wed Nov 29 08:41:22 2000
@@ -268,7 +268,8 @@
    send:	ns_send,
    phy_put:	ns_phy_put,
    phy_get:	ns_phy_get,
-   proc_read:	ns_proc_read
+   proc_read:	ns_proc_read,
+   owner:	THIS_MODULE,
 };
 static struct timer_list ns_timer;
 static char *mac[NS_MAX_CARDS];
@@ -1633,7 +1634,6 @@
    }
    
    set_bit(ATM_VF_READY,&vcc->flags);
-   MOD_INC_USE_COUNT;
    return 0;
 }
 
@@ -1762,7 +1762,6 @@
    vcc->dev_data = NULL;
    clear_bit(ATM_VF_PARTIAL,&vcc->flags);
    clear_bit(ATM_VF_ADDR,&vcc->flags);
-   MOD_DEC_USE_COUNT;
 
 #ifdef RX_DEBUG
    {
diff -u -r linux-2.4.0-test11.clean/include/linux/atm_tcp.h linux-2.4.0-test11.atmrefcount/include/linux/atm_tcp.h
--- linux-2.4.0-test11.clean/include/linux/atm_tcp.h	Wed Feb  9 03:23:13 2000
+++ linux-2.4.0-test11.atmrefcount/include/linux/atm_tcp.h	Wed Nov 29 08:55:45 2000
@@ -65,6 +65,7 @@
 	int (*attach)(struct atm_vcc *vcc,int itf);
 	int (*create_persistent)(int itf);
 	int (*remove_persistent)(int itf);
+	struct module *owner;
 };
 
 extern struct atm_tcp_ops atm_tcp_ops;
diff -u -r linux-2.4.0-test11.clean/include/linux/atmdev.h linux-2.4.0-test11.atmrefcount/include/linux/atmdev.h
--- linux-2.4.0-test11.clean/include/linux/atmdev.h	Sun Nov 19 05:58:55 2000
+++ linux-2.4.0-test11.atmrefcount/include/linux/atmdev.h	Wed Nov 29 08:55:45 2000
@@ -375,6 +375,7 @@
 	void (*free_rx_skb)(struct atm_vcc *vcc, struct sk_buff *skb);
 		/* @@@ temporary hack */
 	int (*proc_read)(struct atm_dev *dev,loff_t *pos,char *page);
+	struct module *owner;
 };
 
 
diff -u -r linux-2.4.0-test11.clean/net/atm/addr.c linux-2.4.0-test11.atmrefcount/net/atm/addr.c
--- linux-2.4.0-test11.clean/net/atm/addr.c	Wed Mar 22 08:38:26 2000
+++ linux-2.4.0-test11.atmrefcount/net/atm/addr.c	Wed Nov 29 08:41:22 2000
@@ -42,7 +42,7 @@
  */
 
 static DECLARE_MUTEX(local_lock);
-
+extern  spinlock_t atm_dev_lock;
 
 static void notify_sigd(struct atm_dev *dev)
 {
@@ -58,12 +58,14 @@
 	struct atm_dev_addr *this;
 
 	down(&local_lock);
+	spin_lock (&atm_dev_lock);		
 	while (dev->local) {
 		this = dev->local;
 		dev->local = this->next;
 		kfree(this);
 	}
 	up(&local_lock);
+	spin_unlock (&atm_dev_lock);
 	notify_sigd(dev);
 }
 
diff -u -r linux-2.4.0-test11.clean/net/atm/common.c linux-2.4.0-test11.atmrefcount/net/atm/common.c
--- linux-2.4.0-test11.clean/net/atm/common.c	Fri Jul  7 06:37:24 2000
+++ linux-2.4.0-test11.atmrefcount/net/atm/common.c	Wed Nov 29 08:41:22 2000
@@ -72,6 +72,7 @@
 #define DPRINTK(format,args...)
 #endif
 
+spinlock_t atm_dev_lock = SPIN_LOCK_UNLOCKED;
 
 static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
 {
@@ -139,13 +140,19 @@
 				vcc->dev->ops->free_rx_skb(vcc,skb);
 			else kfree_skb(skb);
 		}
+		spin_lock (&atm_dev_lock);	
+		fops_put (vcc->dev->ops);
 		if (atomic_read(&vcc->rx_inuse))
 			printk(KERN_WARNING "atm_release_vcc: strange ... "
 			    "rx_inuse == %d after closing\n",
 			    atomic_read(&vcc->rx_inuse));
 		bind_vcc(vcc,NULL);
-	}
+	} else
+		spin_lock (&atm_dev_lock);	
+
 	if (free_sk) free_atm_vcc_sk(sk);
+
+	spin_unlock (&atm_dev_lock);
 }
 
 
@@ -238,9 +245,11 @@
 	    vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu);
 	DPRINTK("  RX: %d, PCR %d..%d, SDU %d\n",vcc->qos.rxtp.traffic_class,
 	    vcc->qos.rxtp.min_pcr,vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu);
+	fops_get (dev->ops);
 	if (dev->ops->open) {
 		error = dev->ops->open(vcc,vpi,vci);
 		if (error) {
+			fops_put (dev->ops);
 			bind_vcc(vcc,NULL);
 			return error;
 		}
@@ -252,10 +261,18 @@
 static int atm_do_connect(struct atm_vcc *vcc,int itf,int vpi,int vci)
 {
 	struct atm_dev *dev;
+	int return_val;
 
+	spin_lock (&atm_dev_lock);
 	dev = atm_find_dev(itf);
-	if (!dev) return -ENODEV;
-	return atm_do_connect_dev(vcc,dev,vpi,vci);
+	if (!dev)
+		return_val =  -ENODEV;
+	else
+		return_val = atm_do_connect_dev(vcc,dev,vpi,vci);
+
+	spin_unlock (&atm_dev_lock);
+
+	return return_val;
 }
 
 
@@ -285,8 +302,10 @@
 	else {
 		struct atm_dev *dev;
 
+		spin_lock (&atm_dev_lock);
 		for (dev = atm_devs; dev; dev = dev->next)
 			if (!atm_do_connect_dev(vcc,dev,vpi,vci)) break;
+		spin_unlock (&atm_dev_lock);
 		if (!dev) return -ENODEV;
 	}
 	if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
@@ -523,57 +542,86 @@
 	struct atm_vcc *vcc;
 	int *tmp_buf;
 	void *buf;
-	int error,len,size,number;
+	int error,len,size,number, ret_val;
 
+	ret_val = 0;
+	spin_lock (&atm_dev_lock);
 	vcc = ATM_SD(sock);
 	switch (cmd) {
 		case SIOCOUTQ:
 			if (sock->state != SS_CONNECTED ||
-			    !test_bit(ATM_VF_READY,&vcc->flags))
-				return -EINVAL;
-			return put_user(vcc->sk->sndbuf-
+			    !test_bit(ATM_VF_READY,&vcc->flags)) {
+				ret_val =  -EINVAL;
+				goto done;
+			}
+			ret_val =  put_user(vcc->sk->sndbuf-
 			    atomic_read(&vcc->tx_inuse)-ATM_PDU_OVHD,
 			    (int *) arg) ? -EFAULT : 0;
+			goto done;
 		case SIOCINQ:
 			{
 				struct sk_buff *skb;
 
-				if (sock->state != SS_CONNECTED)
-					return -EINVAL;
+				if (sock->state != SS_CONNECTED) {
+					ret_val = -EINVAL;
+					goto done;
+				}
 				skb = skb_peek(&vcc->recvq);
-				return put_user(skb ? skb->len : 0,(int *) arg)
+				ret_val = put_user(skb ? skb->len : 0,(int *) arg)
 				    ? -EFAULT : 0;
+				goto done;
 			}
 		case ATM_GETNAMES:
 			if (get_user(buf,
-			    &((struct atm_iobuf *) arg)->buffer))
-				return -EFAULT;
+				     &((struct atm_iobuf *) arg)->buffer)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			if (get_user(len,
-			    &((struct atm_iobuf *) arg)->length))
-				return -EFAULT;
+				     &((struct atm_iobuf *) arg)->length)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			size = 0;
 			for (dev = atm_devs; dev; dev = dev->next)
 				size += sizeof(int);
-			if (size > len) return -E2BIG;
+			if (size > len) {
+				ret_val = -E2BIG;
+				goto done;
+			}
 			tmp_buf = kmalloc(size,GFP_KERNEL);
-			if (!tmp_buf) return -ENOMEM;
+			if (!tmp_buf) {
+				ret_val = -ENOMEM;
+				goto done;
+			}
 			for (dev = atm_devs; dev; dev = dev->next)
 				*tmp_buf++ = dev->number;
-			if (copy_to_user(buf,(char *) tmp_buf-size,size))
-				return -EFAULT;
-			return put_user(size,
+			if (copy_to_user(buf,(char *) tmp_buf-size,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
+		        ret_val = put_user(size,
 			    &((struct atm_iobuf *) arg)->length) ? -EFAULT : 0;
+			goto done;
 		case SIOCGSTAMP: /* borrowed from IP */
-			if (!vcc->timestamp.tv_sec) return -ENOENT;
+			if (!vcc->timestamp.tv_sec) {
+				ret_val = -ENOENT;
+				goto done;
+			}
 			vcc->timestamp.tv_sec += vcc->timestamp.tv_usec/1000000;
 			vcc->timestamp.tv_usec %= 1000000;
-			return copy_to_user((void *) arg,&vcc->timestamp,
+			ret_val = copy_to_user((void *) arg,&vcc->timestamp,
 			    sizeof(struct timeval)) ? -EFAULT : 0;
+			goto done;
 		case ATM_SETSC:
 			printk(KERN_WARNING "ATM_SETSC is obsolete\n");
-			return 0;
+			ret_val = 0;
+			goto done;
 		case ATMSIGD_CTRL:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			/*
 			 * The user/kernel protocol for exchanging signalling
 			 * info uses kernel pointers as opaque references,
@@ -581,175 +629,308 @@
 			 * on the kernel... so we should make sure that we
 			 * have the same privledges that /proc/kcore needs
 			 */
-			if (!capable(CAP_SYS_RAWIO)) return -EPERM;
+			if (!capable(CAP_SYS_RAWIO)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			error = sigd_attach(vcc);
 			if (!error) sock->state = SS_CONNECTED;
-			return error;
+			ret_val = error;
+			goto done;
 #ifdef CONFIG_ATM_CLIP
 		case SIOCMKCLIP:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return clip_create(arg);
+			if (!capable(CAP_NET_ADMIN))
+				ret_val = -EPERM;
+			else 
+				ret_val = clip_create(arg);
+			goto done;
 		case ATMARPD_CTRL:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			error = atm_init_atmarp(vcc);
 			if (!error) sock->state = SS_CONNECTED;
-			return error;
+			ret_val = error;
+			goto done;
 		case ATMARP_MKIP:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return clip_mkip(vcc,arg);
+			if (!capable(CAP_NET_ADMIN)) 
+				ret_val = -EPERM;
+			else 
+				ret_val = clip_mkip(vcc,arg);
+			goto done;
 		case ATMARP_SETENTRY:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return clip_setentry(vcc,arg);
+			if (!capable(CAP_NET_ADMIN)) 
+				ret_val = -EPERM;
+			else
+				ret_val = clip_setentry(vcc,arg);
+			goto done;
 		case ATMARP_ENCAP:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return clip_encap(vcc,arg);
+			if (!capable(CAP_NET_ADMIN)) 
+				ret_val = -EPERM;
+			else
+				ret_val = clip_encap(vcc,arg);
+			goto done;
 #endif
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
                 case ATMLEC_CTRL:
-                        if (!capable(CAP_NET_ADMIN)) return -EPERM;
+                        if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
                         if (atm_lane_ops.lecd_attach == NULL)
                                 atm_lane_init();
-                        if (atm_lane_ops.lecd_attach == NULL) /* try again */
-                                return -ENOSYS;
-                        error = atm_lane_ops.lecd_attach(vcc, (int)arg);
-                        if (error >= 0) sock->state = SS_CONNECTED;
-                        return error;
+                        if (atm_lane_ops.lecd_attach == NULL) { /* try again */
+				ret_val = -ENOSYS;
+				goto done;
+			}
+			error = atm_lane_ops.lecd_attach(vcc, (int)arg);
+			if (error >= 0) sock->state = SS_CONNECTED;
+			ret_val =  error;
+			goto done;
                 case ATMLEC_MCAST:
-                        if (!capable(CAP_NET_ADMIN)) return -EPERM;
-                        return atm_lane_ops.mcast_attach(vcc, (int)arg);
+			if (!capable(CAP_NET_ADMIN))
+				ret_val = -EPERM;
+			else
+				ret_val = atm_lane_ops.mcast_attach(vcc, (int)arg);
+			goto done;
                 case ATMLEC_DATA:
-                        if (!capable(CAP_NET_ADMIN)) return -EPERM;
-                        return atm_lane_ops.vcc_attach(vcc, (void*)arg);
+			if (!capable(CAP_NET_ADMIN))
+				ret_val = -EPERM;
+			else
+				ret_val = atm_lane_ops.vcc_attach(vcc, (void*)arg);
+			goto done;
 #endif
 #if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE)
 		case ATMMPC_CTRL:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-                        if (atm_mpoa_ops.mpoad_attach == NULL)
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
+			if (atm_mpoa_ops.mpoad_attach == NULL)
                                 atm_mpoa_init();
-                        if (atm_mpoa_ops.mpoad_attach == NULL) /* try again */
-                                return -ENOSYS;
-                        error = atm_mpoa_ops.mpoad_attach(vcc, (int)arg);
-                        if (error >= 0) sock->state = SS_CONNECTED;
-                        return error;
+			if (atm_mpoa_ops.mpoad_attach == NULL) { /* try again */
+				ret_val = -ENOSYS;
+				goto done;
+			}
+			error = atm_mpoa_ops.mpoad_attach(vcc, (int)arg);
+			if (error >= 0) sock->state = SS_CONNECTED;
+			ret_val = error;
+			goto done;
 		case ATMMPC_DATA:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return atm_mpoa_ops.vcc_attach(vcc, arg);
+			if (!capable(CAP_NET_ADMIN)) 
+				ret_val = -EPERM;
+			else
+				ret_val = atm_mpoa_ops.vcc_attach(vcc, arg);
+			goto done;
 #endif
 #if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE)
 		case SIOCSIFATMTCP:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			if (!atm_tcp_ops.attach) return -ENOPKG;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
+			if (!atm_tcp_ops.attach) {
+				ret_val = -ENOPKG;
+				goto done;
+			}
+			fops_get (&atm_tcp_ops);
 			error = atm_tcp_ops.attach(vcc,(int) arg);
 			if (error >= 0) sock->state = SS_CONNECTED;
-			return error;
+			else            fops_put (&atm_tcp_ops);
+			ret_val = error;
+			goto done;
 		case ATMTCP_CREATE:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			if (!atm_tcp_ops.create_persistent) return -ENOPKG;
-			return atm_tcp_ops.create_persistent((int) arg);
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
+			if (!atm_tcp_ops.create_persistent) {
+				ret_val = -ENOPKG;
+				goto done;
+			}
+			error = atm_tcp_ops.create_persistent((int) arg);
+			if (error < 0) fops_put (&atm_tcp_ops);
+			ret_val = error;
+			goto done;
 		case ATMTCP_REMOVE:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			if (!atm_tcp_ops.remove_persistent) return -ENOPKG;
-			return atm_tcp_ops.remove_persistent((int) arg);
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
+			if (!atm_tcp_ops.remove_persistent) {
+				ret_val = -ENOPKG;
+				goto done;
+			}
+			error = atm_tcp_ops.remove_persistent((int) arg);
+			fops_put (&atm_tcp_ops);
+			ret_val = error;
+			goto done;
 #endif
 		default:
 			break;
 	}
-	if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) return -EFAULT;
-	if (get_user(len,&((struct atmif_sioc *) arg)->length)) return -EFAULT;
-	if (get_user(number,&((struct atmif_sioc *) arg)->number))
-		return -EFAULT;
-	if (!(dev = atm_find_dev(number))) return -ENODEV;
+	if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) {
+		ret_val = -EFAULT;
+		goto done;
+	}
+	if (get_user(len,&((struct atmif_sioc *) arg)->length)) {
+		ret_val = -EFAULT;
+		goto done;
+	}
+	if (get_user(number,&((struct atmif_sioc *) arg)->number)) {
+		ret_val = -EFAULT;
+		goto done;
+	}
+	if (!(dev = atm_find_dev(number))) {
+		ret_val = -ENODEV;
+		goto done;
+	}
+	
 	size = 0;
 	switch (cmd) {
 		case ATM_GETTYPE:
 			size = strlen(dev->type)+1;
-			if (copy_to_user(buf,dev->type,size)) return -EFAULT;
+			if (copy_to_user(buf,dev->type,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			break;
 		case ATM_GETESI:
 			size = ESI_LEN;
-			if (copy_to_user(buf,dev->esi,size)) return -EFAULT;
+			if (copy_to_user(buf,dev->esi,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			break;
 		case ATM_SETESI:
 			{
 				int i;
 
 				for (i = 0; i < ESI_LEN; i++)
-					if (dev->esi[i]) return -EEXIST;
+					if (dev->esi[i]) {
+						ret_val = -EEXIST;
+						goto done;
+					}
 			}
 			/* fall through */
 		case ATM_SETESIF:
 			{
 				unsigned char esi[ESI_LEN];
 
-				if (!capable(CAP_NET_ADMIN)) return -EPERM;
-				if (copy_from_user(esi,buf,ESI_LEN))
-					return -EFAULT;
+				if (!capable(CAP_NET_ADMIN)) {
+					ret_val = -EPERM;
+					goto done;
+				}
+				if (copy_from_user(esi,buf,ESI_LEN)) {
+					ret_val = -EFAULT;
+					goto done;
+				}
 				memcpy(dev->esi,esi,ESI_LEN);
-				return ESI_LEN;
+				ret_val =  ESI_LEN;
+				goto done;
 			}
 		case ATM_GETSTATZ:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			/* fall through */
 		case ATM_GETSTAT:
 			size = sizeof(struct atm_dev_stats);
 			error = fetch_stats(dev,buf,cmd == ATM_GETSTATZ);
-			if (error) return error;
+			if (error) {
+				ret_val = error;
+				goto done;
+			}
 			break;
 		case ATM_GETCIRANGE:
 			size = sizeof(struct atm_cirange);
-			if (copy_to_user(buf,&dev->ci_range,size))
-				return -EFAULT;
+			if (copy_to_user(buf,&dev->ci_range,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			break;
 		case ATM_GETLINKRATE:
 			size = sizeof(int);
-			if (copy_to_user(buf,&dev->link_rate,size))
-				return -EFAULT;
+			if (copy_to_user(buf,&dev->link_rate,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			break;
 		case ATM_RSTADDR:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			reset_addr(dev);
 			break;
 		case ATM_ADDADDR:
 		case ATM_DELADDR:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			{
 				struct sockaddr_atmsvc addr;
 
-				if (copy_from_user(&addr,buf,sizeof(addr)))
-					return -EFAULT;
+				if (copy_from_user(&addr,buf,sizeof(addr))) {
+					ret_val = -EFAULT;
+					goto done;
+				}
 				if (cmd == ATM_ADDADDR)
-					return add_addr(dev,&addr);
-				else return del_addr(dev,&addr);
+					ret_val = add_addr(dev,&addr);
+				else
+					ret_val = del_addr(dev,&addr);
+				goto done;
 			}
 		case ATM_GETADDR:
 			size = get_addr(dev,buf,len);
-			if (size < 0) return size;
+			if (size < 0)
+				ret_val = size;
+			else
 			/* may return 0, but later on size == 0 means "don't
 			   write the length" */
-			return put_user(size,
-			    &((struct atmif_sioc *) arg)->length) ? -EFAULT : 0;
+				ret_val = put_user(size,
+						   &((struct atmif_sioc *) arg)->length) ? -EFAULT : 0;
+			goto done;
 		case ATM_SETLOOP:
 			if (__ATM_LM_XTRMT((int) (long) buf) &&
 			    __ATM_LM_XTLOC((int) (long) buf) >
-			    __ATM_LM_XTRMT((int) (long) buf))
-				return -EINVAL;
+			    __ATM_LM_XTRMT((int) (long) buf)) {
+				ret_val = -EINVAL;
+				goto done;
+			}
 			/* fall through */
 		case ATM_SETCIRANGE:
 		case SONET_GETSTATZ:
 		case SONET_SETDIAG:
 		case SONET_CLRDIAG:
 		case SONET_SETFRAMING:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			/* fall through */
 		default:
-			if (!dev->ops->ioctl) return -EINVAL;
+			if (!dev->ops->ioctl) {
+				ret_val = -EINVAL;
+				goto done;
+			}
 			size = dev->ops->ioctl(dev,cmd,buf);
-			if (size < 0)
-				return size == -ENOIOCTLCMD ? -EINVAL : size;
+			if (size < 0) {
+				ret_val = (size == -ENOIOCTLCMD ? -EINVAL : size);
+				goto done;
+			}
 	}
-	if (!size) return 0;
-	return put_user(size,&((struct atmif_sioc *) arg)->length) ?
-	    -EFAULT : 0;
+	
+	if (size)
+		ret_val =  put_user(size,&((struct atmif_sioc *) arg)->length) ?
+			-EFAULT : 0;
+
+ done:
+	spin_unlock (&atm_dev_lock); 
+	return ret_val;
 }
 
 
diff -u -r linux-2.4.0-test11.clean/net/atm/resources.c linux-2.4.0-test11.atmrefcount/net/atm/resources.c
--- linux-2.4.0-test11.clean/net/atm/resources.c	Wed Mar 22 08:38:26 2000
+++ linux-2.4.0-test11.atmrefcount/net/atm/resources.c	Wed Nov 29 08:41:22 2000
@@ -25,6 +25,7 @@
 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;
 
 
 static struct atm_dev *alloc_atm_dev(const char *type)
@@ -48,11 +49,15 @@
 
 static void free_atm_dev(struct atm_dev *dev)
 {
+	spin_lock (&atm_dev_lock);
+	
 	if (dev->prev) dev->prev->next = dev->next;
 	else atm_devs = dev->next;
 	if (dev->next) dev->next->prev = dev->prev;
 	else last_dev = dev->prev;
 	kfree(dev);
+	
+	spin_unlock (&atm_dev_lock);
 }
 
 
@@ -100,10 +105,12 @@
 		if (atm_proc_dev_register(dev) < 0) {
 			printk(KERN_ERR "atm_dev_register: "
 			    "atm_proc_dev_register failed for dev %s\n",type);
+			spin_unlock (&atm_dev_lock);		
 			free_atm_dev(dev);
 			return NULL;
 		}
 #endif
+	spin_unlock (&atm_dev_lock);		
 	return dev;
 }
 
diff -u -r linux-2.4.0-test11.clean/net/atm/signaling.c linux-2.4.0-test11.atmrefcount/net/atm/signaling.c
--- linux-2.4.0-test11.clean/net/atm/signaling.c	Wed Nov 15 08:36:01 2000
+++ linux-2.4.0-test11.atmrefcount/net/atm/signaling.c	Wed Nov 29 08:41:22 2000
@@ -33,6 +33,7 @@
 struct atm_vcc *sigd = NULL;
 static DECLARE_WAIT_QUEUE_HEAD(sigd_sleep);
 
+extern spinlock_t atm_dev_lock;
 
 static void sigd_put_skb(struct sk_buff *skb)
 {
@@ -219,7 +220,10 @@
 		printk(KERN_ERR "sigd_close: closing with requests pending\n");
 	while ((skb = skb_dequeue(&vcc->recvq))) kfree_skb(skb);
 	purge_vccs(nodev_vccs);
+
+	spin_lock (&atm_dev_lock);
 	for (dev = atm_devs; dev; dev = dev->next) purge_vccs(dev->vccs);
+	spin_unlock (&atm_dev_lock);
 }
 
 

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH] atmrefcount
@ 2000-11-29  8:58 Patrick van de Lageweg
  0 siblings, 0 replies; 6+ messages in thread
From: Patrick van de Lageweg @ 2000-11-29  8:58 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Rogier Wolff, Linux Kernel Mailing List, Alan Cox

Hi Linus,

This patch contains the fix for the atmrefcount problem (noted as a
critical problem in Ted's todo list).

	Patrick

diff -u -r linux-2.4.0-test11.clean/drivers/atm/ambassador.c linux-2.4.0-test11.atmrefcount/drivers/atm/ambassador.c
--- linux-2.4.0-test11.clean/drivers/atm/ambassador.c	Fri Jul  7 06:37:24 2000
+++ linux-2.4.0-test11.atmrefcount/drivers/atm/ambassador.c	Wed Nov 29 08:41:21 2000
@@ -1251,15 +1251,10 @@
     }
   }
   
-  // prevent module unload while sleeping (kmalloc/down)
-  // doing this any earlier would complicate more error return paths
-  MOD_INC_USE_COUNT;
-  
   // get space for our vcc stuff
   vcc = kmalloc (sizeof(amb_vcc), GFP_KERNEL);
   if (!vcc) {
     PRINTK (KERN_ERR, "out of memory!");
-    MOD_DEC_USE_COUNT;
     return -ENOMEM;
   }
   atm_vcc->dev_data = (void *) vcc;
@@ -1425,7 +1420,6 @@
   // say the VPI/VCI is free again
   clear_bit(ATM_VF_ADDR,&atm_vcc->flags);
 
-  MOD_DEC_USE_COUNT;
   return;
 }
 
@@ -1703,7 +1697,8 @@
   close:	amb_close,
   send:		amb_send,
   sg_send:	amb_sg_send,
-  proc_read:	amb_proc_read
+  proc_read:	amb_proc_read,
+  owner:	THIS_MODULE,
 };
 
 /********** housekeeping **********/
diff -u -r linux-2.4.0-test11.clean/drivers/atm/atmdev_init.c linux-2.4.0-test11.atmrefcount/drivers/atm/atmdev_init.c
--- linux-2.4.0-test11.clean/drivers/atm/atmdev_init.c	Fri Apr 14 18:37:10 2000
+++ linux-2.4.0-test11.atmrefcount/drivers/atm/atmdev_init.c	Wed Nov 29 08:41:21 2000
@@ -54,7 +54,7 @@
 	devs += ia_detect();
 #endif
 #ifdef CONFIG_ATM_FORE200E
-        devs += fore200e_detect();
+	devs += fore200e_detect();
 #endif
 	return devs;
 }
diff -u -r linux-2.4.0-test11.clean/drivers/atm/atmtcp.c linux-2.4.0-test11.atmrefcount/drivers/atm/atmtcp.c
--- linux-2.4.0-test11.clean/drivers/atm/atmtcp.c	Wed Nov 15 08:36:01 2000
+++ linux-2.4.0-test11.atmrefcount/drivers/atm/atmtcp.c	Wed Nov 29 08:41:21 2000
@@ -110,7 +110,7 @@
 
 static void atmtcp_v_dev_close(struct atm_dev *dev)
 {
-	MOD_DEC_USE_COUNT;
+	/* Nothing.... Isn't this simple :-)  -- REW */
 }
 
 
@@ -298,7 +298,8 @@
 	close:		atmtcp_v_close,
 	ioctl:		atmtcp_v_ioctl,
 	send:		atmtcp_v_send,
-	proc_read:	atmtcp_v_proc
+	proc_read:	atmtcp_v_proc,
+	owner:		THIS_MODULE
 };
 
 
@@ -331,18 +332,13 @@
 	struct atmtcp_dev_data *dev_data;
 	struct atm_dev *dev;
 
-	MOD_INC_USE_COUNT;
-
 	dev_data = kmalloc(sizeof(*dev_data),GFP_KERNEL);
-	if (!dev_data) {
-		MOD_DEC_USE_COUNT;
+	if (!dev_data)
 		return -ENOMEM;
-	}
 
 	dev = atm_dev_register(DEV_LABEL,&atmtcp_v_dev_ops,itf,NULL);
 	if (!dev) {
 		kfree(dev_data);
-		MOD_DEC_USE_COUNT;
 		return itf == -1 ? -ENOMEM : -EBUSY;
 	}
 	dev->ci_range.vpi_bits = MAX_VPI_BITS;
diff -u -r linux-2.4.0-test11.clean/drivers/atm/fore200e.c linux-2.4.0-test11.atmrefcount/drivers/atm/fore200e.c
--- linux-2.4.0-test11.clean/drivers/atm/fore200e.c	Mon Oct 16 21:56:50 2000
+++ linux-2.4.0-test11.atmrefcount/drivers/atm/fore200e.c	Wed Nov 29 08:41:21 2000
@@ -1407,8 +1407,6 @@
     struct fore200e*     fore200e = FORE200E_DEV(vcc->dev);
     struct fore200e_vcc* fore200e_vcc;
     
-    MOD_INC_USE_COUNT;
-
     /* find a free VPI/VCI */
     fore200e_walk_vccs(vcc, &vpi, &vci);
 
@@ -1416,10 +1414,8 @@
     vcc->vci = vci;
 
     /* ressource checking only? */
-    if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) {
-    	MOD_DEC_USE_COUNT;
+    if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC)
 	return 0;
-    }
 
     set_bit(ATM_VF_ADDR, &vcc->flags);
     vcc->itf    = vcc->dev->number;
@@ -1437,7 +1433,6 @@
 	down(&fore200e->rate_sf);
 	if (fore200e->available_cell_rate < vcc->qos.txtp.max_pcr) {
 	    up(&fore200e->rate_sf);
-    	    MOD_DEC_USE_COUNT;
 	    return -EAGAIN;
 	}
 	/* reserving the pseudo-CBR bandwidth at this point grants us
@@ -1454,7 +1449,6 @@
 	down(&fore200e->rate_sf);
 	fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
 	up(&fore200e->rate_sf);
-    	MOD_DEC_USE_COUNT;
 	return -ENOMEM;
     }
 
@@ -1465,7 +1459,6 @@
 	down(&fore200e->rate_sf);
 	fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
 	up(&fore200e->rate_sf);
-    	MOD_DEC_USE_COUNT;
 	return -EBUSY;
     }
     
@@ -1498,10 +1491,6 @@
     
     fore200e_activate_vcin(fore200e, 0, vcc, 0);
     
-#ifdef MODULE
-    MOD_DEC_USE_COUNT;
-#endif
-	
     kfree(FORE200E_VCC(vcc));
 	
     if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) {
@@ -2599,8 +2588,6 @@
 
     printk(FORE200E "FORE Systems 200E-series driver - version " FORE200E_VERSION "\n");
 
-    MOD_INC_USE_COUNT;
-
     /* for each configured bus interface */
     for (link = 0, bus = fore200e_bus; bus->model_name; bus++) {
 
@@ -2626,9 +2613,6 @@
 	}
     }
 
-    if (link <= 0)
-	MOD_DEC_USE_COUNT;
-
     return link;
 }
 
@@ -2943,21 +2927,15 @@
 
 static const struct atmdev_ops fore200e_ops =
 {
-    NULL, /* fore200e_dev_close   */
-    fore200e_open,
-    fore200e_close,
-    fore200e_ioctl,
-    fore200e_getsockopt,
-    fore200e_setsockopt,
-    fore200e_send,
-    NULL, /* fore200e_sg_send,    */
-    NULL, /* fore200e_send_oam,   */
-    NULL, /* fore200e_phy_put,    */
-    NULL, /* fore200e_phy_get,    */
-    NULL, /* fore200e_feedback,   */
-    fore200e_change_qos,
-    NULL, /* fore200e_free_rx_skb */
-    fore200e_proc_read
+	open:         fore200e_open,
+	close:        fore200e_close,
+	ioctl:        fore200e_ioctl,
+	getsockopt:   fore200e_getsockopt,
+	setsockopt:   fore200e_setsockopt,
+	send:         fore200e_send,
+	change_qos:   fore200e_change_qos,
+	proc_read:    fore200e_proc_read,
+	owner:        THIS_MODULE,
 };
 
 
diff -u -r linux-2.4.0-test11.clean/drivers/atm/horizon.c linux-2.4.0-test11.atmrefcount/drivers/atm/horizon.c
--- linux-2.4.0-test11.clean/drivers/atm/horizon.c	Fri Jul  7 06:37:24 2000
+++ linux-2.4.0-test11.atmrefcount/drivers/atm/horizon.c	Wed Nov 29 08:41:22 2000
@@ -2491,15 +2491,10 @@
     return -EINVAL;
   }
   
-  // prevent module unload while sleeping (kmalloc)
-  // doing this any earlier would complicate more error return paths
-  MOD_INC_USE_COUNT;
-  
   // get space for our vcc stuff and copy parameters into it
   vccp = kmalloc (sizeof(hrz_vcc), GFP_KERNEL);
   if (!vccp) {
     PRINTK (KERN_ERR, "out of memory!");
-    MOD_DEC_USE_COUNT;
     return -ENOMEM;
   }
   *vccp = vcc;
@@ -2531,7 +2526,6 @@
   if (error) {
     PRINTD (DBG_QOS|DBG_VCC, "insufficient cell rate resources");
     kfree (vccp);
-    MOD_DEC_USE_COUNT;
     return error;
   }
   
@@ -2550,7 +2544,6 @@
       error = hrz_open_rx (dev, channel);
     if (error) {
       kfree (vccp);
-      MOD_DEC_USE_COUNT;
       return error;
     }
     // this link allows RX frames through
@@ -2620,7 +2613,6 @@
   kfree (vcc);
   // say the VPI/VCI is free again
   clear_bit(ATM_VF_ADDR,&atm_vcc->flags);
-  MOD_DEC_USE_COUNT;
 }
 
 #if 0
@@ -2751,7 +2743,8 @@
   close:	hrz_close,
   send:		hrz_send,
   sg_send:	hrz_sg_send,
-  proc_read:	hrz_proc_read
+  proc_read:	hrz_proc_read,
+  owner:	THIS_MODULE,
 };
 
 static int __init hrz_probe (void) {
diff -u -r linux-2.4.0-test11.clean/drivers/atm/iphase.c linux-2.4.0-test11.atmrefcount/drivers/atm/iphase.c
--- linux-2.4.0-test11.clean/drivers/atm/iphase.c	Mon Aug  7 07:20:09 2000
+++ linux-2.4.0-test11.atmrefcount/drivers/atm/iphase.c	Wed Nov 29 08:41:22 2000
@@ -3143,7 +3143,8 @@
 	phy_put:	ia_phy_put,  
 	phy_get:	ia_phy_get,  
 	change_qos:	ia_change_qos,  
-        proc_read:	ia_proc_read
+	proc_read:	ia_proc_read,
+	owner:		THIS_MODULE,
 };  
 	  
   
@@ -3219,7 +3220,6 @@
 		printk(KERN_ERR DEV_LABEL ": no adapter found\n");  
 		return -ENXIO;  
 	}  
-	// MOD_INC_USE_COUNT; 
    	ia_timer.expires = jiffies + 3*HZ;
    	add_timer(&ia_timer); 
    
@@ -3235,7 +3235,6 @@
         int i, j= 0;
  
 	IF_EVENT(printk(">ia cleanup_module\n");)  
-        // MOD_DEC_USE_COUNT;
 	if (MOD_IN_USE)  
 		printk("ia: module in use\n");  
         del_timer(&ia_timer);
diff -u -r linux-2.4.0-test11.clean/drivers/atm/nicstar.c linux-2.4.0-test11.atmrefcount/drivers/atm/nicstar.c
--- linux-2.4.0-test11.clean/drivers/atm/nicstar.c	Tue Nov 14 22:16:33 2000
+++ linux-2.4.0-test11.atmrefcount/drivers/atm/nicstar.c	Wed Nov 29 08:41:22 2000
@@ -268,7 +268,8 @@
    send:	ns_send,
    phy_put:	ns_phy_put,
    phy_get:	ns_phy_get,
-   proc_read:	ns_proc_read
+   proc_read:	ns_proc_read,
+   owner:	THIS_MODULE,
 };
 static struct timer_list ns_timer;
 static char *mac[NS_MAX_CARDS];
@@ -1633,7 +1634,6 @@
    }
    
    set_bit(ATM_VF_READY,&vcc->flags);
-   MOD_INC_USE_COUNT;
    return 0;
 }
 
@@ -1762,7 +1762,6 @@
    vcc->dev_data = NULL;
    clear_bit(ATM_VF_PARTIAL,&vcc->flags);
    clear_bit(ATM_VF_ADDR,&vcc->flags);
-   MOD_DEC_USE_COUNT;
 
 #ifdef RX_DEBUG
    {
diff -u -r linux-2.4.0-test11.clean/include/linux/atm_tcp.h linux-2.4.0-test11.atmrefcount/include/linux/atm_tcp.h
--- linux-2.4.0-test11.clean/include/linux/atm_tcp.h	Wed Feb  9 03:23:13 2000
+++ linux-2.4.0-test11.atmrefcount/include/linux/atm_tcp.h	Wed Nov 29 08:55:45 2000
@@ -65,6 +65,7 @@
 	int (*attach)(struct atm_vcc *vcc,int itf);
 	int (*create_persistent)(int itf);
 	int (*remove_persistent)(int itf);
+	struct module *owner;
 };
 
 extern struct atm_tcp_ops atm_tcp_ops;
diff -u -r linux-2.4.0-test11.clean/include/linux/atmdev.h linux-2.4.0-test11.atmrefcount/include/linux/atmdev.h
--- linux-2.4.0-test11.clean/include/linux/atmdev.h	Sun Nov 19 05:58:55 2000
+++ linux-2.4.0-test11.atmrefcount/include/linux/atmdev.h	Wed Nov 29 08:55:45 2000
@@ -375,6 +375,7 @@
 	void (*free_rx_skb)(struct atm_vcc *vcc, struct sk_buff *skb);
 		/* @@@ temporary hack */
 	int (*proc_read)(struct atm_dev *dev,loff_t *pos,char *page);
+	struct module *owner;
 };
 
 
diff -u -r linux-2.4.0-test11.clean/net/atm/addr.c linux-2.4.0-test11.atmrefcount/net/atm/addr.c
--- linux-2.4.0-test11.clean/net/atm/addr.c	Wed Mar 22 08:38:26 2000
+++ linux-2.4.0-test11.atmrefcount/net/atm/addr.c	Wed Nov 29 08:41:22 2000
@@ -42,7 +42,7 @@
  */
 
 static DECLARE_MUTEX(local_lock);
-
+extern  spinlock_t atm_dev_lock;
 
 static void notify_sigd(struct atm_dev *dev)
 {
@@ -58,12 +58,14 @@
 	struct atm_dev_addr *this;
 
 	down(&local_lock);
+	spin_lock (&atm_dev_lock);		
 	while (dev->local) {
 		this = dev->local;
 		dev->local = this->next;
 		kfree(this);
 	}
 	up(&local_lock);
+	spin_unlock (&atm_dev_lock);
 	notify_sigd(dev);
 }
 
diff -u -r linux-2.4.0-test11.clean/net/atm/common.c linux-2.4.0-test11.atmrefcount/net/atm/common.c
--- linux-2.4.0-test11.clean/net/atm/common.c	Fri Jul  7 06:37:24 2000
+++ linux-2.4.0-test11.atmrefcount/net/atm/common.c	Wed Nov 29 08:41:22 2000
@@ -72,6 +72,7 @@
 #define DPRINTK(format,args...)
 #endif
 
+spinlock_t atm_dev_lock = SPIN_LOCK_UNLOCKED;
 
 static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
 {
@@ -139,13 +140,19 @@
 				vcc->dev->ops->free_rx_skb(vcc,skb);
 			else kfree_skb(skb);
 		}
+		spin_lock (&atm_dev_lock);	
+		fops_put (vcc->dev->ops);
 		if (atomic_read(&vcc->rx_inuse))
 			printk(KERN_WARNING "atm_release_vcc: strange ... "
 			    "rx_inuse == %d after closing\n",
 			    atomic_read(&vcc->rx_inuse));
 		bind_vcc(vcc,NULL);
-	}
+	} else
+		spin_lock (&atm_dev_lock);	
+
 	if (free_sk) free_atm_vcc_sk(sk);
+
+	spin_unlock (&atm_dev_lock);
 }
 
 
@@ -238,9 +245,11 @@
 	    vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu);
 	DPRINTK("  RX: %d, PCR %d..%d, SDU %d\n",vcc->qos.rxtp.traffic_class,
 	    vcc->qos.rxtp.min_pcr,vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu);
+	fops_get (dev->ops);
 	if (dev->ops->open) {
 		error = dev->ops->open(vcc,vpi,vci);
 		if (error) {
+			fops_put (dev->ops);
 			bind_vcc(vcc,NULL);
 			return error;
 		}
@@ -252,10 +261,18 @@
 static int atm_do_connect(struct atm_vcc *vcc,int itf,int vpi,int vci)
 {
 	struct atm_dev *dev;
+	int return_val;
 
+	spin_lock (&atm_dev_lock);
 	dev = atm_find_dev(itf);
-	if (!dev) return -ENODEV;
-	return atm_do_connect_dev(vcc,dev,vpi,vci);
+	if (!dev)
+		return_val =  -ENODEV;
+	else
+		return_val = atm_do_connect_dev(vcc,dev,vpi,vci);
+
+	spin_unlock (&atm_dev_lock);
+
+	return return_val;
 }
 
 
@@ -285,8 +302,10 @@
 	else {
 		struct atm_dev *dev;
 
+		spin_lock (&atm_dev_lock);
 		for (dev = atm_devs; dev; dev = dev->next)
 			if (!atm_do_connect_dev(vcc,dev,vpi,vci)) break;
+		spin_unlock (&atm_dev_lock);
 		if (!dev) return -ENODEV;
 	}
 	if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
@@ -523,57 +542,86 @@
 	struct atm_vcc *vcc;
 	int *tmp_buf;
 	void *buf;
-	int error,len,size,number;
+	int error,len,size,number, ret_val;
 
+	ret_val = 0;
+	spin_lock (&atm_dev_lock);
 	vcc = ATM_SD(sock);
 	switch (cmd) {
 		case SIOCOUTQ:
 			if (sock->state != SS_CONNECTED ||
-			    !test_bit(ATM_VF_READY,&vcc->flags))
-				return -EINVAL;
-			return put_user(vcc->sk->sndbuf-
+			    !test_bit(ATM_VF_READY,&vcc->flags)) {
+				ret_val =  -EINVAL;
+				goto done;
+			}
+			ret_val =  put_user(vcc->sk->sndbuf-
 			    atomic_read(&vcc->tx_inuse)-ATM_PDU_OVHD,
 			    (int *) arg) ? -EFAULT : 0;
+			goto done;
 		case SIOCINQ:
 			{
 				struct sk_buff *skb;
 
-				if (sock->state != SS_CONNECTED)
-					return -EINVAL;
+				if (sock->state != SS_CONNECTED) {
+					ret_val = -EINVAL;
+					goto done;
+				}
 				skb = skb_peek(&vcc->recvq);
-				return put_user(skb ? skb->len : 0,(int *) arg)
+				ret_val = put_user(skb ? skb->len : 0,(int *) arg)
 				    ? -EFAULT : 0;
+				goto done;
 			}
 		case ATM_GETNAMES:
 			if (get_user(buf,
-			    &((struct atm_iobuf *) arg)->buffer))
-				return -EFAULT;
+				     &((struct atm_iobuf *) arg)->buffer)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			if (get_user(len,
-			    &((struct atm_iobuf *) arg)->length))
-				return -EFAULT;
+				     &((struct atm_iobuf *) arg)->length)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			size = 0;
 			for (dev = atm_devs; dev; dev = dev->next)
 				size += sizeof(int);
-			if (size > len) return -E2BIG;
+			if (size > len) {
+				ret_val = -E2BIG;
+				goto done;
+			}
 			tmp_buf = kmalloc(size,GFP_KERNEL);
-			if (!tmp_buf) return -ENOMEM;
+			if (!tmp_buf) {
+				ret_val = -ENOMEM;
+				goto done;
+			}
 			for (dev = atm_devs; dev; dev = dev->next)
 				*tmp_buf++ = dev->number;
-			if (copy_to_user(buf,(char *) tmp_buf-size,size))
-				return -EFAULT;
-			return put_user(size,
+			if (copy_to_user(buf,(char *) tmp_buf-size,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
+		        ret_val = put_user(size,
 			    &((struct atm_iobuf *) arg)->length) ? -EFAULT : 0;
+			goto done;
 		case SIOCGSTAMP: /* borrowed from IP */
-			if (!vcc->timestamp.tv_sec) return -ENOENT;
+			if (!vcc->timestamp.tv_sec) {
+				ret_val = -ENOENT;
+				goto done;
+			}
 			vcc->timestamp.tv_sec += vcc->timestamp.tv_usec/1000000;
 			vcc->timestamp.tv_usec %= 1000000;
-			return copy_to_user((void *) arg,&vcc->timestamp,
+			ret_val = copy_to_user((void *) arg,&vcc->timestamp,
 			    sizeof(struct timeval)) ? -EFAULT : 0;
+			goto done;
 		case ATM_SETSC:
 			printk(KERN_WARNING "ATM_SETSC is obsolete\n");
-			return 0;
+			ret_val = 0;
+			goto done;
 		case ATMSIGD_CTRL:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			/*
 			 * The user/kernel protocol for exchanging signalling
 			 * info uses kernel pointers as opaque references,
@@ -581,175 +629,308 @@
 			 * on the kernel... so we should make sure that we
 			 * have the same privledges that /proc/kcore needs
 			 */
-			if (!capable(CAP_SYS_RAWIO)) return -EPERM;
+			if (!capable(CAP_SYS_RAWIO)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			error = sigd_attach(vcc);
 			if (!error) sock->state = SS_CONNECTED;
-			return error;
+			ret_val = error;
+			goto done;
 #ifdef CONFIG_ATM_CLIP
 		case SIOCMKCLIP:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return clip_create(arg);
+			if (!capable(CAP_NET_ADMIN))
+				ret_val = -EPERM;
+			else 
+				ret_val = clip_create(arg);
+			goto done;
 		case ATMARPD_CTRL:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			error = atm_init_atmarp(vcc);
 			if (!error) sock->state = SS_CONNECTED;
-			return error;
+			ret_val = error;
+			goto done;
 		case ATMARP_MKIP:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return clip_mkip(vcc,arg);
+			if (!capable(CAP_NET_ADMIN)) 
+				ret_val = -EPERM;
+			else 
+				ret_val = clip_mkip(vcc,arg);
+			goto done;
 		case ATMARP_SETENTRY:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return clip_setentry(vcc,arg);
+			if (!capable(CAP_NET_ADMIN)) 
+				ret_val = -EPERM;
+			else
+				ret_val = clip_setentry(vcc,arg);
+			goto done;
 		case ATMARP_ENCAP:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return clip_encap(vcc,arg);
+			if (!capable(CAP_NET_ADMIN)) 
+				ret_val = -EPERM;
+			else
+				ret_val = clip_encap(vcc,arg);
+			goto done;
 #endif
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
                 case ATMLEC_CTRL:
-                        if (!capable(CAP_NET_ADMIN)) return -EPERM;
+                        if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
                         if (atm_lane_ops.lecd_attach == NULL)
                                 atm_lane_init();
-                        if (atm_lane_ops.lecd_attach == NULL) /* try again */
-                                return -ENOSYS;
-                        error = atm_lane_ops.lecd_attach(vcc, (int)arg);
-                        if (error >= 0) sock->state = SS_CONNECTED;
-                        return error;
+                        if (atm_lane_ops.lecd_attach == NULL) { /* try again */
+				ret_val = -ENOSYS;
+				goto done;
+			}
+			error = atm_lane_ops.lecd_attach(vcc, (int)arg);
+			if (error >= 0) sock->state = SS_CONNECTED;
+			ret_val =  error;
+			goto done;
                 case ATMLEC_MCAST:
-                        if (!capable(CAP_NET_ADMIN)) return -EPERM;
-                        return atm_lane_ops.mcast_attach(vcc, (int)arg);
+			if (!capable(CAP_NET_ADMIN))
+				ret_val = -EPERM;
+			else
+				ret_val = atm_lane_ops.mcast_attach(vcc, (int)arg);
+			goto done;
                 case ATMLEC_DATA:
-                        if (!capable(CAP_NET_ADMIN)) return -EPERM;
-                        return atm_lane_ops.vcc_attach(vcc, (void*)arg);
+			if (!capable(CAP_NET_ADMIN))
+				ret_val = -EPERM;
+			else
+				ret_val = atm_lane_ops.vcc_attach(vcc, (void*)arg);
+			goto done;
 #endif
 #if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE)
 		case ATMMPC_CTRL:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-                        if (atm_mpoa_ops.mpoad_attach == NULL)
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
+			if (atm_mpoa_ops.mpoad_attach == NULL)
                                 atm_mpoa_init();
-                        if (atm_mpoa_ops.mpoad_attach == NULL) /* try again */
-                                return -ENOSYS;
-                        error = atm_mpoa_ops.mpoad_attach(vcc, (int)arg);
-                        if (error >= 0) sock->state = SS_CONNECTED;
-                        return error;
+			if (atm_mpoa_ops.mpoad_attach == NULL) { /* try again */
+				ret_val = -ENOSYS;
+				goto done;
+			}
+			error = atm_mpoa_ops.mpoad_attach(vcc, (int)arg);
+			if (error >= 0) sock->state = SS_CONNECTED;
+			ret_val = error;
+			goto done;
 		case ATMMPC_DATA:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return atm_mpoa_ops.vcc_attach(vcc, arg);
+			if (!capable(CAP_NET_ADMIN)) 
+				ret_val = -EPERM;
+			else
+				ret_val = atm_mpoa_ops.vcc_attach(vcc, arg);
+			goto done;
 #endif
 #if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE)
 		case SIOCSIFATMTCP:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			if (!atm_tcp_ops.attach) return -ENOPKG;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
+			if (!atm_tcp_ops.attach) {
+				ret_val = -ENOPKG;
+				goto done;
+			}
+			fops_get (&atm_tcp_ops);
 			error = atm_tcp_ops.attach(vcc,(int) arg);
 			if (error >= 0) sock->state = SS_CONNECTED;
-			return error;
+			else            fops_put (&atm_tcp_ops);
+			ret_val = error;
+			goto done;
 		case ATMTCP_CREATE:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			if (!atm_tcp_ops.create_persistent) return -ENOPKG;
-			return atm_tcp_ops.create_persistent((int) arg);
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
+			if (!atm_tcp_ops.create_persistent) {
+				ret_val = -ENOPKG;
+				goto done;
+			}
+			error = atm_tcp_ops.create_persistent((int) arg);
+			if (error < 0) fops_put (&atm_tcp_ops);
+			ret_val = error;
+			goto done;
 		case ATMTCP_REMOVE:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			if (!atm_tcp_ops.remove_persistent) return -ENOPKG;
-			return atm_tcp_ops.remove_persistent((int) arg);
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
+			if (!atm_tcp_ops.remove_persistent) {
+				ret_val = -ENOPKG;
+				goto done;
+			}
+			error = atm_tcp_ops.remove_persistent((int) arg);
+			fops_put (&atm_tcp_ops);
+			ret_val = error;
+			goto done;
 #endif
 		default:
 			break;
 	}
-	if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) return -EFAULT;
-	if (get_user(len,&((struct atmif_sioc *) arg)->length)) return -EFAULT;
-	if (get_user(number,&((struct atmif_sioc *) arg)->number))
-		return -EFAULT;
-	if (!(dev = atm_find_dev(number))) return -ENODEV;
+	if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) {
+		ret_val = -EFAULT;
+		goto done;
+	}
+	if (get_user(len,&((struct atmif_sioc *) arg)->length)) {
+		ret_val = -EFAULT;
+		goto done;
+	}
+	if (get_user(number,&((struct atmif_sioc *) arg)->number)) {
+		ret_val = -EFAULT;
+		goto done;
+	}
+	if (!(dev = atm_find_dev(number))) {
+		ret_val = -ENODEV;
+		goto done;
+	}
+	
 	size = 0;
 	switch (cmd) {
 		case ATM_GETTYPE:
 			size = strlen(dev->type)+1;
-			if (copy_to_user(buf,dev->type,size)) return -EFAULT;
+			if (copy_to_user(buf,dev->type,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			break;
 		case ATM_GETESI:
 			size = ESI_LEN;
-			if (copy_to_user(buf,dev->esi,size)) return -EFAULT;
+			if (copy_to_user(buf,dev->esi,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			break;
 		case ATM_SETESI:
 			{
 				int i;
 
 				for (i = 0; i < ESI_LEN; i++)
-					if (dev->esi[i]) return -EEXIST;
+					if (dev->esi[i]) {
+						ret_val = -EEXIST;
+						goto done;
+					}
 			}
 			/* fall through */
 		case ATM_SETESIF:
 			{
 				unsigned char esi[ESI_LEN];
 
-				if (!capable(CAP_NET_ADMIN)) return -EPERM;
-				if (copy_from_user(esi,buf,ESI_LEN))
-					return -EFAULT;
+				if (!capable(CAP_NET_ADMIN)) {
+					ret_val = -EPERM;
+					goto done;
+				}
+				if (copy_from_user(esi,buf,ESI_LEN)) {
+					ret_val = -EFAULT;
+					goto done;
+				}
 				memcpy(dev->esi,esi,ESI_LEN);
-				return ESI_LEN;
+				ret_val =  ESI_LEN;
+				goto done;
 			}
 		case ATM_GETSTATZ:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			/* fall through */
 		case ATM_GETSTAT:
 			size = sizeof(struct atm_dev_stats);
 			error = fetch_stats(dev,buf,cmd == ATM_GETSTATZ);
-			if (error) return error;
+			if (error) {
+				ret_val = error;
+				goto done;
+			}
 			break;
 		case ATM_GETCIRANGE:
 			size = sizeof(struct atm_cirange);
-			if (copy_to_user(buf,&dev->ci_range,size))
-				return -EFAULT;
+			if (copy_to_user(buf,&dev->ci_range,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			break;
 		case ATM_GETLINKRATE:
 			size = sizeof(int);
-			if (copy_to_user(buf,&dev->link_rate,size))
-				return -EFAULT;
+			if (copy_to_user(buf,&dev->link_rate,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			break;
 		case ATM_RSTADDR:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			reset_addr(dev);
 			break;
 		case ATM_ADDADDR:
 		case ATM_DELADDR:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			{
 				struct sockaddr_atmsvc addr;
 
-				if (copy_from_user(&addr,buf,sizeof(addr)))
-					return -EFAULT;
+				if (copy_from_user(&addr,buf,sizeof(addr))) {
+					ret_val = -EFAULT;
+					goto done;
+				}
 				if (cmd == ATM_ADDADDR)
-					return add_addr(dev,&addr);
-				else return del_addr(dev,&addr);
+					ret_val = add_addr(dev,&addr);
+				else
+					ret_val = del_addr(dev,&addr);
+				goto done;
 			}
 		case ATM_GETADDR:
 			size = get_addr(dev,buf,len);
-			if (size < 0) return size;
+			if (size < 0)
+				ret_val = size;
+			else
 			/* may return 0, but later on size == 0 means "don't
 			   write the length" */
-			return put_user(size,
-			    &((struct atmif_sioc *) arg)->length) ? -EFAULT : 0;
+				ret_val = put_user(size,
+						   &((struct atmif_sioc *) arg)->length) ? -EFAULT : 0;
+			goto done;
 		case ATM_SETLOOP:
 			if (__ATM_LM_XTRMT((int) (long) buf) &&
 			    __ATM_LM_XTLOC((int) (long) buf) >
-			    __ATM_LM_XTRMT((int) (long) buf))
-				return -EINVAL;
+			    __ATM_LM_XTRMT((int) (long) buf)) {
+				ret_val = -EINVAL;
+				goto done;
+			}
 			/* fall through */
 		case ATM_SETCIRANGE:
 		case SONET_GETSTATZ:
 		case SONET_SETDIAG:
 		case SONET_CLRDIAG:
 		case SONET_SETFRAMING:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			/* fall through */
 		default:
-			if (!dev->ops->ioctl) return -EINVAL;
+			if (!dev->ops->ioctl) {
+				ret_val = -EINVAL;
+				goto done;
+			}
 			size = dev->ops->ioctl(dev,cmd,buf);
-			if (size < 0)
-				return size == -ENOIOCTLCMD ? -EINVAL : size;
+			if (size < 0) {
+				ret_val = (size == -ENOIOCTLCMD ? -EINVAL : size);
+				goto done;
+			}
 	}
-	if (!size) return 0;
-	return put_user(size,&((struct atmif_sioc *) arg)->length) ?
-	    -EFAULT : 0;
+	
+	if (size)
+		ret_val =  put_user(size,&((struct atmif_sioc *) arg)->length) ?
+			-EFAULT : 0;
+
+ done:
+	spin_unlock (&atm_dev_lock); 
+	return ret_val;
 }
 
 
diff -u -r linux-2.4.0-test11.clean/net/atm/resources.c linux-2.4.0-test11.atmrefcount/net/atm/resources.c
--- linux-2.4.0-test11.clean/net/atm/resources.c	Wed Mar 22 08:38:26 2000
+++ linux-2.4.0-test11.atmrefcount/net/atm/resources.c	Wed Nov 29 08:41:22 2000
@@ -25,6 +25,7 @@
 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;
 
 
 static struct atm_dev *alloc_atm_dev(const char *type)
@@ -48,11 +49,15 @@
 
 static void free_atm_dev(struct atm_dev *dev)
 {
+	spin_lock (&atm_dev_lock);
+	
 	if (dev->prev) dev->prev->next = dev->next;
 	else atm_devs = dev->next;
 	if (dev->next) dev->next->prev = dev->prev;
 	else last_dev = dev->prev;
 	kfree(dev);
+	
+	spin_unlock (&atm_dev_lock);
 }
 
 
@@ -100,10 +105,12 @@
 		if (atm_proc_dev_register(dev) < 0) {
 			printk(KERN_ERR "atm_dev_register: "
 			    "atm_proc_dev_register failed for dev %s\n",type);
+			spin_unlock (&atm_dev_lock);		
 			free_atm_dev(dev);
 			return NULL;
 		}
 #endif
+	spin_unlock (&atm_dev_lock);		
 	return dev;
 }
 
diff -u -r linux-2.4.0-test11.clean/net/atm/signaling.c linux-2.4.0-test11.atmrefcount/net/atm/signaling.c
--- linux-2.4.0-test11.clean/net/atm/signaling.c	Wed Nov 15 08:36:01 2000
+++ linux-2.4.0-test11.atmrefcount/net/atm/signaling.c	Wed Nov 29 08:41:22 2000
@@ -33,6 +33,7 @@
 struct atm_vcc *sigd = NULL;
 static DECLARE_WAIT_QUEUE_HEAD(sigd_sleep);
 
+extern spinlock_t atm_dev_lock;
 
 static void sigd_put_skb(struct sk_buff *skb)
 {
@@ -219,7 +220,10 @@
 		printk(KERN_ERR "sigd_close: closing with requests pending\n");
 	while ((skb = skb_dequeue(&vcc->recvq))) kfree_skb(skb);
 	purge_vccs(nodev_vccs);
+
+	spin_lock (&atm_dev_lock);
 	for (dev = atm_devs; dev; dev = dev->next) purge_vccs(dev->vccs);
+	spin_unlock (&atm_dev_lock);
 }
 
 


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH] atmrefcount
@ 2000-12-12 15:44 Patrick van de Lageweg
  0 siblings, 0 replies; 6+ messages in thread
From: Patrick van de Lageweg @ 2000-12-12 15:44 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Rogier Wolff, Alan Cox, Linux Kernel Mailing List

Hi Linus,

This patch contains the fix for the atmrefcount problem (noted as a
critical problem in Ted's todo list).

	Patrick

diff -u -r linux-2.4.0-test11.clean/drivers/atm/ambassador.c linux-2.4.0-test11.atmrefcount/drivers/atm/ambassador.c
--- linux-2.4.0-test11.clean/drivers/atm/ambassador.c	Fri Jul  7 06:37:24 2000
+++ linux-2.4.0-test11.atmrefcount/drivers/atm/ambassador.c	Wed Nov 29 08:41:21 2000
@@ -1251,15 +1251,10 @@
     }
   }
   
-  // prevent module unload while sleeping (kmalloc/down)
-  // doing this any earlier would complicate more error return paths
-  MOD_INC_USE_COUNT;
-  
   // get space for our vcc stuff
   vcc = kmalloc (sizeof(amb_vcc), GFP_KERNEL);
   if (!vcc) {
     PRINTK (KERN_ERR, "out of memory!");
-    MOD_DEC_USE_COUNT;
     return -ENOMEM;
   }
   atm_vcc->dev_data = (void *) vcc;
@@ -1425,7 +1420,6 @@
   // say the VPI/VCI is free again
   clear_bit(ATM_VF_ADDR,&atm_vcc->flags);
 
-  MOD_DEC_USE_COUNT;
   return;
 }
 
@@ -1703,7 +1697,8 @@
   close:	amb_close,
   send:		amb_send,
   sg_send:	amb_sg_send,
-  proc_read:	amb_proc_read
+  proc_read:	amb_proc_read,
+  owner:	THIS_MODULE,
 };
 
 /********** housekeeping **********/
diff -u -r linux-2.4.0-test11.clean/drivers/atm/atmdev_init.c linux-2.4.0-test11.atmrefcount/drivers/atm/atmdev_init.c
--- linux-2.4.0-test11.clean/drivers/atm/atmdev_init.c	Fri Apr 14 18:37:10 2000
+++ linux-2.4.0-test11.atmrefcount/drivers/atm/atmdev_init.c	Wed Nov 29 08:41:21 2000
@@ -54,7 +54,7 @@
 	devs += ia_detect();
 #endif
 #ifdef CONFIG_ATM_FORE200E
-        devs += fore200e_detect();
+	devs += fore200e_detect();
 #endif
 	return devs;
 }
diff -u -r linux-2.4.0-test11.clean/drivers/atm/atmtcp.c linux-2.4.0-test11.atmrefcount/drivers/atm/atmtcp.c
--- linux-2.4.0-test11.clean/drivers/atm/atmtcp.c	Wed Nov 15 08:36:01 2000
+++ linux-2.4.0-test11.atmrefcount/drivers/atm/atmtcp.c	Wed Nov 29 08:41:21 2000
@@ -110,7 +110,7 @@
 
 static void atmtcp_v_dev_close(struct atm_dev *dev)
 {
-	MOD_DEC_USE_COUNT;
+	/* Nothing.... Isn't this simple :-)  -- REW */
 }
 
 
@@ -298,7 +298,8 @@
 	close:		atmtcp_v_close,
 	ioctl:		atmtcp_v_ioctl,
 	send:		atmtcp_v_send,
-	proc_read:	atmtcp_v_proc
+	proc_read:	atmtcp_v_proc,
+	owner:		THIS_MODULE
 };
 
 
@@ -331,18 +332,13 @@
 	struct atmtcp_dev_data *dev_data;
 	struct atm_dev *dev;
 
-	MOD_INC_USE_COUNT;
-
 	dev_data = kmalloc(sizeof(*dev_data),GFP_KERNEL);
-	if (!dev_data) {
-		MOD_DEC_USE_COUNT;
+	if (!dev_data)
 		return -ENOMEM;
-	}
 
 	dev = atm_dev_register(DEV_LABEL,&atmtcp_v_dev_ops,itf,NULL);
 	if (!dev) {
 		kfree(dev_data);
-		MOD_DEC_USE_COUNT;
 		return itf == -1 ? -ENOMEM : -EBUSY;
 	}
 	dev->ci_range.vpi_bits = MAX_VPI_BITS;
diff -u -r linux-2.4.0-test11.clean/drivers/atm/fore200e.c linux-2.4.0-test11.atmrefcount/drivers/atm/fore200e.c
--- linux-2.4.0-test11.clean/drivers/atm/fore200e.c	Mon Oct 16 21:56:50 2000
+++ linux-2.4.0-test11.atmrefcount/drivers/atm/fore200e.c	Wed Nov 29 08:41:21 2000
@@ -1407,8 +1407,6 @@
     struct fore200e*     fore200e = FORE200E_DEV(vcc->dev);
     struct fore200e_vcc* fore200e_vcc;
     
-    MOD_INC_USE_COUNT;
-
     /* find a free VPI/VCI */
     fore200e_walk_vccs(vcc, &vpi, &vci);
 
@@ -1416,10 +1414,8 @@
     vcc->vci = vci;
 
     /* ressource checking only? */
-    if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) {
-    	MOD_DEC_USE_COUNT;
+    if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC)
 	return 0;
-    }
 
     set_bit(ATM_VF_ADDR, &vcc->flags);
     vcc->itf    = vcc->dev->number;
@@ -1437,7 +1433,6 @@
 	down(&fore200e->rate_sf);
 	if (fore200e->available_cell_rate < vcc->qos.txtp.max_pcr) {
 	    up(&fore200e->rate_sf);
-    	    MOD_DEC_USE_COUNT;
 	    return -EAGAIN;
 	}
 	/* reserving the pseudo-CBR bandwidth at this point grants us
@@ -1454,7 +1449,6 @@
 	down(&fore200e->rate_sf);
 	fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
 	up(&fore200e->rate_sf);
-    	MOD_DEC_USE_COUNT;
 	return -ENOMEM;
     }
 
@@ -1465,7 +1459,6 @@
 	down(&fore200e->rate_sf);
 	fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
 	up(&fore200e->rate_sf);
-    	MOD_DEC_USE_COUNT;
 	return -EBUSY;
     }
     
@@ -1498,10 +1491,6 @@
     
     fore200e_activate_vcin(fore200e, 0, vcc, 0);
     
-#ifdef MODULE
-    MOD_DEC_USE_COUNT;
-#endif
-	
     kfree(FORE200E_VCC(vcc));
 	
     if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) {
@@ -2599,8 +2588,6 @@
 
     printk(FORE200E "FORE Systems 200E-series driver - version " FORE200E_VERSION "\n");
 
-    MOD_INC_USE_COUNT;
-
     /* for each configured bus interface */
     for (link = 0, bus = fore200e_bus; bus->model_name; bus++) {
 
@@ -2626,9 +2613,6 @@
 	}
     }
 
-    if (link <= 0)
-	MOD_DEC_USE_COUNT;
-
     return link;
 }
 
@@ -2943,21 +2927,15 @@
 
 static const struct atmdev_ops fore200e_ops =
 {
-    NULL, /* fore200e_dev_close   */
-    fore200e_open,
-    fore200e_close,
-    fore200e_ioctl,
-    fore200e_getsockopt,
-    fore200e_setsockopt,
-    fore200e_send,
-    NULL, /* fore200e_sg_send,    */
-    NULL, /* fore200e_send_oam,   */
-    NULL, /* fore200e_phy_put,    */
-    NULL, /* fore200e_phy_get,    */
-    NULL, /* fore200e_feedback,   */
-    fore200e_change_qos,
-    NULL, /* fore200e_free_rx_skb */
-    fore200e_proc_read
+	open:         fore200e_open,
+	close:        fore200e_close,
+	ioctl:        fore200e_ioctl,
+	getsockopt:   fore200e_getsockopt,
+	setsockopt:   fore200e_setsockopt,
+	send:         fore200e_send,
+	change_qos:   fore200e_change_qos,
+	proc_read:    fore200e_proc_read,
+	owner:        THIS_MODULE,
 };
 
 
diff -u -r linux-2.4.0-test11.clean/drivers/atm/horizon.c linux-2.4.0-test11.atmrefcount/drivers/atm/horizon.c
--- linux-2.4.0-test11.clean/drivers/atm/horizon.c	Fri Jul  7 06:37:24 2000
+++ linux-2.4.0-test11.atmrefcount/drivers/atm/horizon.c	Wed Nov 29 08:41:22 2000
@@ -2491,15 +2491,10 @@
     return -EINVAL;
   }
   
-  // prevent module unload while sleeping (kmalloc)
-  // doing this any earlier would complicate more error return paths
-  MOD_INC_USE_COUNT;
-  
   // get space for our vcc stuff and copy parameters into it
   vccp = kmalloc (sizeof(hrz_vcc), GFP_KERNEL);
   if (!vccp) {
     PRINTK (KERN_ERR, "out of memory!");
-    MOD_DEC_USE_COUNT;
     return -ENOMEM;
   }
   *vccp = vcc;
@@ -2531,7 +2526,6 @@
   if (error) {
     PRINTD (DBG_QOS|DBG_VCC, "insufficient cell rate resources");
     kfree (vccp);
-    MOD_DEC_USE_COUNT;
     return error;
   }
   
@@ -2550,7 +2544,6 @@
       error = hrz_open_rx (dev, channel);
     if (error) {
       kfree (vccp);
-      MOD_DEC_USE_COUNT;
       return error;
     }
     // this link allows RX frames through
@@ -2620,7 +2613,6 @@
   kfree (vcc);
   // say the VPI/VCI is free again
   clear_bit(ATM_VF_ADDR,&atm_vcc->flags);
-  MOD_DEC_USE_COUNT;
 }
 
 #if 0
@@ -2751,7 +2743,8 @@
   close:	hrz_close,
   send:		hrz_send,
   sg_send:	hrz_sg_send,
-  proc_read:	hrz_proc_read
+  proc_read:	hrz_proc_read,
+  owner:	THIS_MODULE,
 };
 
 static int __init hrz_probe (void) {
diff -u -r linux-2.4.0-test11.clean/drivers/atm/iphase.c linux-2.4.0-test11.atmrefcount/drivers/atm/iphase.c
--- linux-2.4.0-test11.clean/drivers/atm/iphase.c	Mon Aug  7 07:20:09 2000
+++ linux-2.4.0-test11.atmrefcount/drivers/atm/iphase.c	Wed Nov 29 08:41:22 2000
@@ -3143,7 +3143,8 @@
 	phy_put:	ia_phy_put,  
 	phy_get:	ia_phy_get,  
 	change_qos:	ia_change_qos,  
-        proc_read:	ia_proc_read
+	proc_read:	ia_proc_read,
+	owner:		THIS_MODULE,
 };  
 	  
   
@@ -3219,7 +3220,6 @@
 		printk(KERN_ERR DEV_LABEL ": no adapter found\n");  
 		return -ENXIO;  
 	}  
-	// MOD_INC_USE_COUNT; 
    	ia_timer.expires = jiffies + 3*HZ;
    	add_timer(&ia_timer); 
    
@@ -3235,7 +3235,6 @@
         int i, j= 0;
  
 	IF_EVENT(printk(">ia cleanup_module\n");)  
-        // MOD_DEC_USE_COUNT;
 	if (MOD_IN_USE)  
 		printk("ia: module in use\n");  
         del_timer(&ia_timer);
diff -u -r linux-2.4.0-test11.clean/drivers/atm/nicstar.c linux-2.4.0-test11.atmrefcount/drivers/atm/nicstar.c
--- linux-2.4.0-test11.clean/drivers/atm/nicstar.c	Tue Nov 14 22:16:33 2000
+++ linux-2.4.0-test11.atmrefcount/drivers/atm/nicstar.c	Wed Nov 29 08:41:22 2000
@@ -268,7 +268,8 @@
    send:	ns_send,
    phy_put:	ns_phy_put,
    phy_get:	ns_phy_get,
-   proc_read:	ns_proc_read
+   proc_read:	ns_proc_read,
+   owner:	THIS_MODULE,
 };
 static struct timer_list ns_timer;
 static char *mac[NS_MAX_CARDS];
@@ -1633,7 +1634,6 @@
    }
    
    set_bit(ATM_VF_READY,&vcc->flags);
-   MOD_INC_USE_COUNT;
    return 0;
 }
 
@@ -1762,7 +1762,6 @@
    vcc->dev_data = NULL;
    clear_bit(ATM_VF_PARTIAL,&vcc->flags);
    clear_bit(ATM_VF_ADDR,&vcc->flags);
-   MOD_DEC_USE_COUNT;
 
 #ifdef RX_DEBUG
    {
diff -u -r linux-2.4.0-test11.clean/include/linux/atm_tcp.h linux-2.4.0-test11.atmrefcount/include/linux/atm_tcp.h
--- linux-2.4.0-test11.clean/include/linux/atm_tcp.h	Wed Feb  9 03:23:13 2000
+++ linux-2.4.0-test11.atmrefcount/include/linux/atm_tcp.h	Wed Nov 29 08:55:45 2000
@@ -65,6 +65,7 @@
 	int (*attach)(struct atm_vcc *vcc,int itf);
 	int (*create_persistent)(int itf);
 	int (*remove_persistent)(int itf);
+	struct module *owner;
 };
 
 extern struct atm_tcp_ops atm_tcp_ops;
diff -u -r linux-2.4.0-test11.clean/include/linux/atmdev.h linux-2.4.0-test11.atmrefcount/include/linux/atmdev.h
--- linux-2.4.0-test11.clean/include/linux/atmdev.h	Sun Nov 19 05:58:55 2000
+++ linux-2.4.0-test11.atmrefcount/include/linux/atmdev.h	Wed Nov 29 08:55:45 2000
@@ -375,6 +375,7 @@
 	void (*free_rx_skb)(struct atm_vcc *vcc, struct sk_buff *skb);
 		/* @@@ temporary hack */
 	int (*proc_read)(struct atm_dev *dev,loff_t *pos,char *page);
+	struct module *owner;
 };
 
 
diff -u -r linux-2.4.0-test11.clean/net/atm/addr.c linux-2.4.0-test11.atmrefcount/net/atm/addr.c
--- linux-2.4.0-test11.clean/net/atm/addr.c	Wed Mar 22 08:38:26 2000
+++ linux-2.4.0-test11.atmrefcount/net/atm/addr.c	Wed Nov 29 08:41:22 2000
@@ -42,7 +42,7 @@
  */
 
 static DECLARE_MUTEX(local_lock);
-
+extern  spinlock_t atm_dev_lock;
 
 static void notify_sigd(struct atm_dev *dev)
 {
@@ -58,12 +58,14 @@
 	struct atm_dev_addr *this;
 
 	down(&local_lock);
+	spin_lock (&atm_dev_lock);		
 	while (dev->local) {
 		this = dev->local;
 		dev->local = this->next;
 		kfree(this);
 	}
 	up(&local_lock);
+	spin_unlock (&atm_dev_lock);
 	notify_sigd(dev);
 }
 
diff -u -r linux-2.4.0-test11.clean/net/atm/common.c linux-2.4.0-test11.atmrefcount/net/atm/common.c
--- linux-2.4.0-test11.clean/net/atm/common.c	Fri Jul  7 06:37:24 2000
+++ linux-2.4.0-test11.atmrefcount/net/atm/common.c	Wed Nov 29 08:41:22 2000
@@ -72,6 +72,7 @@
 #define DPRINTK(format,args...)
 #endif
 
+spinlock_t atm_dev_lock = SPIN_LOCK_UNLOCKED;
 
 static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
 {
@@ -139,13 +140,19 @@
 				vcc->dev->ops->free_rx_skb(vcc,skb);
 			else kfree_skb(skb);
 		}
+		spin_lock (&atm_dev_lock);	
+		fops_put (vcc->dev->ops);
 		if (atomic_read(&vcc->rx_inuse))
 			printk(KERN_WARNING "atm_release_vcc: strange ... "
 			    "rx_inuse == %d after closing\n",
 			    atomic_read(&vcc->rx_inuse));
 		bind_vcc(vcc,NULL);
-	}
+	} else
+		spin_lock (&atm_dev_lock);	
+
 	if (free_sk) free_atm_vcc_sk(sk);
+
+	spin_unlock (&atm_dev_lock);
 }
 
 
@@ -238,9 +245,11 @@
 	    vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu);
 	DPRINTK("  RX: %d, PCR %d..%d, SDU %d\n",vcc->qos.rxtp.traffic_class,
 	    vcc->qos.rxtp.min_pcr,vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu);
+	fops_get (dev->ops);
 	if (dev->ops->open) {
 		error = dev->ops->open(vcc,vpi,vci);
 		if (error) {
+			fops_put (dev->ops);
 			bind_vcc(vcc,NULL);
 			return error;
 		}
@@ -252,10 +261,18 @@
 static int atm_do_connect(struct atm_vcc *vcc,int itf,int vpi,int vci)
 {
 	struct atm_dev *dev;
+	int return_val;
 
+	spin_lock (&atm_dev_lock);
 	dev = atm_find_dev(itf);
-	if (!dev) return -ENODEV;
-	return atm_do_connect_dev(vcc,dev,vpi,vci);
+	if (!dev)
+		return_val =  -ENODEV;
+	else
+		return_val = atm_do_connect_dev(vcc,dev,vpi,vci);
+
+	spin_unlock (&atm_dev_lock);
+
+	return return_val;
 }
 
 
@@ -285,8 +302,10 @@
 	else {
 		struct atm_dev *dev;
 
+		spin_lock (&atm_dev_lock);
 		for (dev = atm_devs; dev; dev = dev->next)
 			if (!atm_do_connect_dev(vcc,dev,vpi,vci)) break;
+		spin_unlock (&atm_dev_lock);
 		if (!dev) return -ENODEV;
 	}
 	if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
@@ -523,57 +542,86 @@
 	struct atm_vcc *vcc;
 	int *tmp_buf;
 	void *buf;
-	int error,len,size,number;
+	int error,len,size,number, ret_val;
 
+	ret_val = 0;
+	spin_lock (&atm_dev_lock);
 	vcc = ATM_SD(sock);
 	switch (cmd) {
 		case SIOCOUTQ:
 			if (sock->state != SS_CONNECTED ||
-			    !test_bit(ATM_VF_READY,&vcc->flags))
-				return -EINVAL;
-			return put_user(vcc->sk->sndbuf-
+			    !test_bit(ATM_VF_READY,&vcc->flags)) {
+				ret_val =  -EINVAL;
+				goto done;
+			}
+			ret_val =  put_user(vcc->sk->sndbuf-
 			    atomic_read(&vcc->tx_inuse)-ATM_PDU_OVHD,
 			    (int *) arg) ? -EFAULT : 0;
+			goto done;
 		case SIOCINQ:
 			{
 				struct sk_buff *skb;
 
-				if (sock->state != SS_CONNECTED)
-					return -EINVAL;
+				if (sock->state != SS_CONNECTED) {
+					ret_val = -EINVAL;
+					goto done;
+				}
 				skb = skb_peek(&vcc->recvq);
-				return put_user(skb ? skb->len : 0,(int *) arg)
+				ret_val = put_user(skb ? skb->len : 0,(int *) arg)
 				    ? -EFAULT : 0;
+				goto done;
 			}
 		case ATM_GETNAMES:
 			if (get_user(buf,
-			    &((struct atm_iobuf *) arg)->buffer))
-				return -EFAULT;
+				     &((struct atm_iobuf *) arg)->buffer)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			if (get_user(len,
-			    &((struct atm_iobuf *) arg)->length))
-				return -EFAULT;
+				     &((struct atm_iobuf *) arg)->length)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			size = 0;
 			for (dev = atm_devs; dev; dev = dev->next)
 				size += sizeof(int);
-			if (size > len) return -E2BIG;
+			if (size > len) {
+				ret_val = -E2BIG;
+				goto done;
+			}
 			tmp_buf = kmalloc(size,GFP_KERNEL);
-			if (!tmp_buf) return -ENOMEM;
+			if (!tmp_buf) {
+				ret_val = -ENOMEM;
+				goto done;
+			}
 			for (dev = atm_devs; dev; dev = dev->next)
 				*tmp_buf++ = dev->number;
-			if (copy_to_user(buf,(char *) tmp_buf-size,size))
-				return -EFAULT;
-			return put_user(size,
+			if (copy_to_user(buf,(char *) tmp_buf-size,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
+		        ret_val = put_user(size,
 			    &((struct atm_iobuf *) arg)->length) ? -EFAULT : 0;
+			goto done;
 		case SIOCGSTAMP: /* borrowed from IP */
-			if (!vcc->timestamp.tv_sec) return -ENOENT;
+			if (!vcc->timestamp.tv_sec) {
+				ret_val = -ENOENT;
+				goto done;
+			}
 			vcc->timestamp.tv_sec += vcc->timestamp.tv_usec/1000000;
 			vcc->timestamp.tv_usec %= 1000000;
-			return copy_to_user((void *) arg,&vcc->timestamp,
+			ret_val = copy_to_user((void *) arg,&vcc->timestamp,
 			    sizeof(struct timeval)) ? -EFAULT : 0;
+			goto done;
 		case ATM_SETSC:
 			printk(KERN_WARNING "ATM_SETSC is obsolete\n");
-			return 0;
+			ret_val = 0;
+			goto done;
 		case ATMSIGD_CTRL:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			/*
 			 * The user/kernel protocol for exchanging signalling
 			 * info uses kernel pointers as opaque references,
@@ -581,175 +629,308 @@
 			 * on the kernel... so we should make sure that we
 			 * have the same privledges that /proc/kcore needs
 			 */
-			if (!capable(CAP_SYS_RAWIO)) return -EPERM;
+			if (!capable(CAP_SYS_RAWIO)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			error = sigd_attach(vcc);
 			if (!error) sock->state = SS_CONNECTED;
-			return error;
+			ret_val = error;
+			goto done;
 #ifdef CONFIG_ATM_CLIP
 		case SIOCMKCLIP:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return clip_create(arg);
+			if (!capable(CAP_NET_ADMIN))
+				ret_val = -EPERM;
+			else 
+				ret_val = clip_create(arg);
+			goto done;
 		case ATMARPD_CTRL:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			error = atm_init_atmarp(vcc);
 			if (!error) sock->state = SS_CONNECTED;
-			return error;
+			ret_val = error;
+			goto done;
 		case ATMARP_MKIP:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return clip_mkip(vcc,arg);
+			if (!capable(CAP_NET_ADMIN)) 
+				ret_val = -EPERM;
+			else 
+				ret_val = clip_mkip(vcc,arg);
+			goto done;
 		case ATMARP_SETENTRY:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return clip_setentry(vcc,arg);
+			if (!capable(CAP_NET_ADMIN)) 
+				ret_val = -EPERM;
+			else
+				ret_val = clip_setentry(vcc,arg);
+			goto done;
 		case ATMARP_ENCAP:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return clip_encap(vcc,arg);
+			if (!capable(CAP_NET_ADMIN)) 
+				ret_val = -EPERM;
+			else
+				ret_val = clip_encap(vcc,arg);
+			goto done;
 #endif
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
                 case ATMLEC_CTRL:
-                        if (!capable(CAP_NET_ADMIN)) return -EPERM;
+                        if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
                         if (atm_lane_ops.lecd_attach == NULL)
                                 atm_lane_init();
-                        if (atm_lane_ops.lecd_attach == NULL) /* try again */
-                                return -ENOSYS;
-                        error = atm_lane_ops.lecd_attach(vcc, (int)arg);
-                        if (error >= 0) sock->state = SS_CONNECTED;
-                        return error;
+                        if (atm_lane_ops.lecd_attach == NULL) { /* try again */
+				ret_val = -ENOSYS;
+				goto done;
+			}
+			error = atm_lane_ops.lecd_attach(vcc, (int)arg);
+			if (error >= 0) sock->state = SS_CONNECTED;
+			ret_val =  error;
+			goto done;
                 case ATMLEC_MCAST:
-                        if (!capable(CAP_NET_ADMIN)) return -EPERM;
-                        return atm_lane_ops.mcast_attach(vcc, (int)arg);
+			if (!capable(CAP_NET_ADMIN))
+				ret_val = -EPERM;
+			else
+				ret_val = atm_lane_ops.mcast_attach(vcc, (int)arg);
+			goto done;
                 case ATMLEC_DATA:
-                        if (!capable(CAP_NET_ADMIN)) return -EPERM;
-                        return atm_lane_ops.vcc_attach(vcc, (void*)arg);
+			if (!capable(CAP_NET_ADMIN))
+				ret_val = -EPERM;
+			else
+				ret_val = atm_lane_ops.vcc_attach(vcc, (void*)arg);
+			goto done;
 #endif
 #if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE)
 		case ATMMPC_CTRL:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-                        if (atm_mpoa_ops.mpoad_attach == NULL)
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
+			if (atm_mpoa_ops.mpoad_attach == NULL)
                                 atm_mpoa_init();
-                        if (atm_mpoa_ops.mpoad_attach == NULL) /* try again */
-                                return -ENOSYS;
-                        error = atm_mpoa_ops.mpoad_attach(vcc, (int)arg);
-                        if (error >= 0) sock->state = SS_CONNECTED;
-                        return error;
+			if (atm_mpoa_ops.mpoad_attach == NULL) { /* try again */
+				ret_val = -ENOSYS;
+				goto done;
+			}
+			error = atm_mpoa_ops.mpoad_attach(vcc, (int)arg);
+			if (error >= 0) sock->state = SS_CONNECTED;
+			ret_val = error;
+			goto done;
 		case ATMMPC_DATA:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return atm_mpoa_ops.vcc_attach(vcc, arg);
+			if (!capable(CAP_NET_ADMIN)) 
+				ret_val = -EPERM;
+			else
+				ret_val = atm_mpoa_ops.vcc_attach(vcc, arg);
+			goto done;
 #endif
 #if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE)
 		case SIOCSIFATMTCP:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			if (!atm_tcp_ops.attach) return -ENOPKG;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
+			if (!atm_tcp_ops.attach) {
+				ret_val = -ENOPKG;
+				goto done;
+			}
+			fops_get (&atm_tcp_ops);
 			error = atm_tcp_ops.attach(vcc,(int) arg);
 			if (error >= 0) sock->state = SS_CONNECTED;
-			return error;
+			else            fops_put (&atm_tcp_ops);
+			ret_val = error;
+			goto done;
 		case ATMTCP_CREATE:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			if (!atm_tcp_ops.create_persistent) return -ENOPKG;
-			return atm_tcp_ops.create_persistent((int) arg);
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
+			if (!atm_tcp_ops.create_persistent) {
+				ret_val = -ENOPKG;
+				goto done;
+			}
+			error = atm_tcp_ops.create_persistent((int) arg);
+			if (error < 0) fops_put (&atm_tcp_ops);
+			ret_val = error;
+			goto done;
 		case ATMTCP_REMOVE:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			if (!atm_tcp_ops.remove_persistent) return -ENOPKG;
-			return atm_tcp_ops.remove_persistent((int) arg);
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
+			if (!atm_tcp_ops.remove_persistent) {
+				ret_val = -ENOPKG;
+				goto done;
+			}
+			error = atm_tcp_ops.remove_persistent((int) arg);
+			fops_put (&atm_tcp_ops);
+			ret_val = error;
+			goto done;
 #endif
 		default:
 			break;
 	}
-	if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) return -EFAULT;
-	if (get_user(len,&((struct atmif_sioc *) arg)->length)) return -EFAULT;
-	if (get_user(number,&((struct atmif_sioc *) arg)->number))
-		return -EFAULT;
-	if (!(dev = atm_find_dev(number))) return -ENODEV;
+	if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) {
+		ret_val = -EFAULT;
+		goto done;
+	}
+	if (get_user(len,&((struct atmif_sioc *) arg)->length)) {
+		ret_val = -EFAULT;
+		goto done;
+	}
+	if (get_user(number,&((struct atmif_sioc *) arg)->number)) {
+		ret_val = -EFAULT;
+		goto done;
+	}
+	if (!(dev = atm_find_dev(number))) {
+		ret_val = -ENODEV;
+		goto done;
+	}
+	
 	size = 0;
 	switch (cmd) {
 		case ATM_GETTYPE:
 			size = strlen(dev->type)+1;
-			if (copy_to_user(buf,dev->type,size)) return -EFAULT;
+			if (copy_to_user(buf,dev->type,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			break;
 		case ATM_GETESI:
 			size = ESI_LEN;
-			if (copy_to_user(buf,dev->esi,size)) return -EFAULT;
+			if (copy_to_user(buf,dev->esi,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			break;
 		case ATM_SETESI:
 			{
 				int i;
 
 				for (i = 0; i < ESI_LEN; i++)
-					if (dev->esi[i]) return -EEXIST;
+					if (dev->esi[i]) {
+						ret_val = -EEXIST;
+						goto done;
+					}
 			}
 			/* fall through */
 		case ATM_SETESIF:
 			{
 				unsigned char esi[ESI_LEN];
 
-				if (!capable(CAP_NET_ADMIN)) return -EPERM;
-				if (copy_from_user(esi,buf,ESI_LEN))
-					return -EFAULT;
+				if (!capable(CAP_NET_ADMIN)) {
+					ret_val = -EPERM;
+					goto done;
+				}
+				if (copy_from_user(esi,buf,ESI_LEN)) {
+					ret_val = -EFAULT;
+					goto done;
+				}
 				memcpy(dev->esi,esi,ESI_LEN);
-				return ESI_LEN;
+				ret_val =  ESI_LEN;
+				goto done;
 			}
 		case ATM_GETSTATZ:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			/* fall through */
 		case ATM_GETSTAT:
 			size = sizeof(struct atm_dev_stats);
 			error = fetch_stats(dev,buf,cmd == ATM_GETSTATZ);
-			if (error) return error;
+			if (error) {
+				ret_val = error;
+				goto done;
+			}
 			break;
 		case ATM_GETCIRANGE:
 			size = sizeof(struct atm_cirange);
-			if (copy_to_user(buf,&dev->ci_range,size))
-				return -EFAULT;
+			if (copy_to_user(buf,&dev->ci_range,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			break;
 		case ATM_GETLINKRATE:
 			size = sizeof(int);
-			if (copy_to_user(buf,&dev->link_rate,size))
-				return -EFAULT;
+			if (copy_to_user(buf,&dev->link_rate,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			break;
 		case ATM_RSTADDR:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			reset_addr(dev);
 			break;
 		case ATM_ADDADDR:
 		case ATM_DELADDR:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			{
 				struct sockaddr_atmsvc addr;
 
-				if (copy_from_user(&addr,buf,sizeof(addr)))
-					return -EFAULT;
+				if (copy_from_user(&addr,buf,sizeof(addr))) {
+					ret_val = -EFAULT;
+					goto done;
+				}
 				if (cmd == ATM_ADDADDR)
-					return add_addr(dev,&addr);
-				else return del_addr(dev,&addr);
+					ret_val = add_addr(dev,&addr);
+				else
+					ret_val = del_addr(dev,&addr);
+				goto done;
 			}
 		case ATM_GETADDR:
 			size = get_addr(dev,buf,len);
-			if (size < 0) return size;
+			if (size < 0)
+				ret_val = size;
+			else
 			/* may return 0, but later on size == 0 means "don't
 			   write the length" */
-			return put_user(size,
-			    &((struct atmif_sioc *) arg)->length) ? -EFAULT : 0;
+				ret_val = put_user(size,
+						   &((struct atmif_sioc *) arg)->length) ? -EFAULT : 0;
+			goto done;
 		case ATM_SETLOOP:
 			if (__ATM_LM_XTRMT((int) (long) buf) &&
 			    __ATM_LM_XTLOC((int) (long) buf) >
-			    __ATM_LM_XTRMT((int) (long) buf))
-				return -EINVAL;
+			    __ATM_LM_XTRMT((int) (long) buf)) {
+				ret_val = -EINVAL;
+				goto done;
+			}
 			/* fall through */
 		case ATM_SETCIRANGE:
 		case SONET_GETSTATZ:
 		case SONET_SETDIAG:
 		case SONET_CLRDIAG:
 		case SONET_SETFRAMING:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			/* fall through */
 		default:
-			if (!dev->ops->ioctl) return -EINVAL;
+			if (!dev->ops->ioctl) {
+				ret_val = -EINVAL;
+				goto done;
+			}
 			size = dev->ops->ioctl(dev,cmd,buf);
-			if (size < 0)
-				return size == -ENOIOCTLCMD ? -EINVAL : size;
+			if (size < 0) {
+				ret_val = (size == -ENOIOCTLCMD ? -EINVAL : size);
+				goto done;
+			}
 	}
-	if (!size) return 0;
-	return put_user(size,&((struct atmif_sioc *) arg)->length) ?
-	    -EFAULT : 0;
+	
+	if (size)
+		ret_val =  put_user(size,&((struct atmif_sioc *) arg)->length) ?
+			-EFAULT : 0;
+
+ done:
+	spin_unlock (&atm_dev_lock); 
+	return ret_val;
 }
 
 
diff -u -r linux-2.4.0-test11.clean/net/atm/resources.c linux-2.4.0-test11.atmrefcount/net/atm/resources.c
--- linux-2.4.0-test11.clean/net/atm/resources.c	Wed Mar 22 08:38:26 2000
+++ linux-2.4.0-test11.atmrefcount/net/atm/resources.c	Wed Nov 29 08:41:22 2000
@@ -25,6 +25,7 @@
 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;
 
 
 static struct atm_dev *alloc_atm_dev(const char *type)
@@ -48,11 +49,15 @@
 
 static void free_atm_dev(struct atm_dev *dev)
 {
+	spin_lock (&atm_dev_lock);
+	
 	if (dev->prev) dev->prev->next = dev->next;
 	else atm_devs = dev->next;
 	if (dev->next) dev->next->prev = dev->prev;
 	else last_dev = dev->prev;
 	kfree(dev);
+	
+	spin_unlock (&atm_dev_lock);
 }
 
 
@@ -100,10 +105,12 @@
 		if (atm_proc_dev_register(dev) < 0) {
 			printk(KERN_ERR "atm_dev_register: "
 			    "atm_proc_dev_register failed for dev %s\n",type);
+			spin_unlock (&atm_dev_lock);		
 			free_atm_dev(dev);
 			return NULL;
 		}
 #endif
+	spin_unlock (&atm_dev_lock);		
 	return dev;
 }
 
diff -u -r linux-2.4.0-test11.clean/net/atm/signaling.c linux-2.4.0-test11.atmrefcount/net/atm/signaling.c
--- linux-2.4.0-test11.clean/net/atm/signaling.c	Wed Nov 15 08:36:01 2000
+++ linux-2.4.0-test11.atmrefcount/net/atm/signaling.c	Wed Nov 29 08:41:22 2000
@@ -33,6 +33,7 @@
 struct atm_vcc *sigd = NULL;
 static DECLARE_WAIT_QUEUE_HEAD(sigd_sleep);
 
+extern spinlock_t atm_dev_lock;
 
 static void sigd_put_skb(struct sk_buff *skb)
 {
@@ -219,7 +220,10 @@
 		printk(KERN_ERR "sigd_close: closing with requests pending\n");
 	while ((skb = skb_dequeue(&vcc->recvq))) kfree_skb(skb);
 	purge_vccs(nodev_vccs);
+
+	spin_lock (&atm_dev_lock);
 	for (dev = atm_devs; dev; dev = dev->next) purge_vccs(dev->vccs);
+	spin_unlock (&atm_dev_lock);
 }
 
 






-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH] atmrefcount
@ 2000-12-15 12:03 Patrick van de Lageweg
  0 siblings, 0 replies; 6+ messages in thread
From: Patrick van de Lageweg @ 2000-12-15 12:03 UTC (permalink / raw)
  To: Alan Cox, Rogier Wolff, Linux Kernel Mailing List

Hi Linus,

This patch contains the fix for the atmrefcount problem (noted as a
critical problem in Ted's todo list).

	Patrick

diff -u -r linux-2.4.0-test13-pre1.clean/drivers/atm/ambassador.c linux-2.4.0-test13-pre1.atm-refcount/drivers/atm/ambassador.c
--- linux-2.4.0-test13-pre1.clean/drivers/atm/ambassador.c	Thu Dec 14 09:36:56 2000
+++ linux-2.4.0-test13-pre1.atm-refcount/drivers/atm/ambassador.c	Thu Dec 14 12:54:37 2000
@@ -1251,15 +1251,10 @@
     }
   }
   
-  // prevent module unload while sleeping (kmalloc/down)
-  // doing this any earlier would complicate more error return paths
-  MOD_INC_USE_COUNT;
-  
   // get space for our vcc stuff
   vcc = kmalloc (sizeof(amb_vcc), GFP_KERNEL);
   if (!vcc) {
     PRINTK (KERN_ERR, "out of memory!");
-    MOD_DEC_USE_COUNT;
     return -ENOMEM;
   }
   atm_vcc->dev_data = (void *) vcc;
@@ -1425,7 +1420,6 @@
   // say the VPI/VCI is free again
   clear_bit(ATM_VF_ADDR,&atm_vcc->flags);
 
-  MOD_DEC_USE_COUNT;
   return;
 }
 
@@ -1703,7 +1697,8 @@
   close:	amb_close,
   send:		amb_send,
   sg_send:	amb_sg_send,
-  proc_read:	amb_proc_read
+  proc_read:	amb_proc_read,
+  owner:	THIS_MODULE,
 };
 
 /********** housekeeping **********/
diff -u -r linux-2.4.0-test13-pre1.clean/drivers/atm/atmdev_init.c linux-2.4.0-test13-pre1.atm-refcount/drivers/atm/atmdev_init.c
--- linux-2.4.0-test13-pre1.clean/drivers/atm/atmdev_init.c	Fri Apr 14 18:37:10 2000
+++ linux-2.4.0-test13-pre1.atm-refcount/drivers/atm/atmdev_init.c	Thu Dec 14 12:54:37 2000
@@ -54,7 +54,7 @@
 	devs += ia_detect();
 #endif
 #ifdef CONFIG_ATM_FORE200E
-        devs += fore200e_detect();
+	devs += fore200e_detect();
 #endif
 	return devs;
 }
diff -u -r linux-2.4.0-test13-pre1.clean/drivers/atm/atmtcp.c linux-2.4.0-test13-pre1.atm-refcount/drivers/atm/atmtcp.c
--- linux-2.4.0-test13-pre1.clean/drivers/atm/atmtcp.c	Wed Nov 15 08:36:01 2000
+++ linux-2.4.0-test13-pre1.atm-refcount/drivers/atm/atmtcp.c	Thu Dec 14 12:54:37 2000
@@ -110,7 +110,7 @@
 
 static void atmtcp_v_dev_close(struct atm_dev *dev)
 {
-	MOD_DEC_USE_COUNT;
+	/* Nothing.... Isn't this simple :-)  -- REW */
 }
 
 
@@ -298,7 +298,8 @@
 	close:		atmtcp_v_close,
 	ioctl:		atmtcp_v_ioctl,
 	send:		atmtcp_v_send,
-	proc_read:	atmtcp_v_proc
+	proc_read:	atmtcp_v_proc,
+	owner:		THIS_MODULE
 };
 
 
@@ -331,18 +332,13 @@
 	struct atmtcp_dev_data *dev_data;
 	struct atm_dev *dev;
 
-	MOD_INC_USE_COUNT;
-
 	dev_data = kmalloc(sizeof(*dev_data),GFP_KERNEL);
-	if (!dev_data) {
-		MOD_DEC_USE_COUNT;
+	if (!dev_data)
 		return -ENOMEM;
-	}
 
 	dev = atm_dev_register(DEV_LABEL,&atmtcp_v_dev_ops,itf,NULL);
 	if (!dev) {
 		kfree(dev_data);
-		MOD_DEC_USE_COUNT;
 		return itf == -1 ? -ENOMEM : -EBUSY;
 	}
 	dev->ci_range.vpi_bits = MAX_VPI_BITS;
diff -u -r linux-2.4.0-test13-pre1.clean/drivers/atm/fore200e.c linux-2.4.0-test13-pre1.atm-refcount/drivers/atm/fore200e.c
--- linux-2.4.0-test13-pre1.clean/drivers/atm/fore200e.c	Mon Oct 16 21:56:50 2000
+++ linux-2.4.0-test13-pre1.atm-refcount/drivers/atm/fore200e.c	Thu Dec 14 12:54:37 2000
@@ -1407,8 +1407,6 @@
     struct fore200e*     fore200e = FORE200E_DEV(vcc->dev);
     struct fore200e_vcc* fore200e_vcc;
     
-    MOD_INC_USE_COUNT;
-
     /* find a free VPI/VCI */
     fore200e_walk_vccs(vcc, &vpi, &vci);
 
@@ -1416,10 +1414,8 @@
     vcc->vci = vci;
 
     /* ressource checking only? */
-    if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) {
-    	MOD_DEC_USE_COUNT;
+    if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC)
 	return 0;
-    }
 
     set_bit(ATM_VF_ADDR, &vcc->flags);
     vcc->itf    = vcc->dev->number;
@@ -1437,7 +1433,6 @@
 	down(&fore200e->rate_sf);
 	if (fore200e->available_cell_rate < vcc->qos.txtp.max_pcr) {
 	    up(&fore200e->rate_sf);
-    	    MOD_DEC_USE_COUNT;
 	    return -EAGAIN;
 	}
 	/* reserving the pseudo-CBR bandwidth at this point grants us
@@ -1454,7 +1449,6 @@
 	down(&fore200e->rate_sf);
 	fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
 	up(&fore200e->rate_sf);
-    	MOD_DEC_USE_COUNT;
 	return -ENOMEM;
     }
 
@@ -1465,7 +1459,6 @@
 	down(&fore200e->rate_sf);
 	fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
 	up(&fore200e->rate_sf);
-    	MOD_DEC_USE_COUNT;
 	return -EBUSY;
     }
     
@@ -1498,10 +1491,6 @@
     
     fore200e_activate_vcin(fore200e, 0, vcc, 0);
     
-#ifdef MODULE
-    MOD_DEC_USE_COUNT;
-#endif
-	
     kfree(FORE200E_VCC(vcc));
 	
     if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) {
@@ -2599,8 +2588,6 @@
 
     printk(FORE200E "FORE Systems 200E-series driver - version " FORE200E_VERSION "\n");
 
-    MOD_INC_USE_COUNT;
-
     /* for each configured bus interface */
     for (link = 0, bus = fore200e_bus; bus->model_name; bus++) {
 
@@ -2626,9 +2613,6 @@
 	}
     }
 
-    if (link <= 0)
-	MOD_DEC_USE_COUNT;
-
     return link;
 }
 
@@ -2943,21 +2927,15 @@
 
 static const struct atmdev_ops fore200e_ops =
 {
-    NULL, /* fore200e_dev_close   */
-    fore200e_open,
-    fore200e_close,
-    fore200e_ioctl,
-    fore200e_getsockopt,
-    fore200e_setsockopt,
-    fore200e_send,
-    NULL, /* fore200e_sg_send,    */
-    NULL, /* fore200e_send_oam,   */
-    NULL, /* fore200e_phy_put,    */
-    NULL, /* fore200e_phy_get,    */
-    NULL, /* fore200e_feedback,   */
-    fore200e_change_qos,
-    NULL, /* fore200e_free_rx_skb */
-    fore200e_proc_read
+	open:         fore200e_open,
+	close:        fore200e_close,
+	ioctl:        fore200e_ioctl,
+	getsockopt:   fore200e_getsockopt,
+	setsockopt:   fore200e_setsockopt,
+	send:         fore200e_send,
+	change_qos:   fore200e_change_qos,
+	proc_read:    fore200e_proc_read,
+	owner:        THIS_MODULE,
 };
 
 
diff -u -r linux-2.4.0-test13-pre1.clean/drivers/atm/horizon.c linux-2.4.0-test13-pre1.atm-refcount/drivers/atm/horizon.c
--- linux-2.4.0-test13-pre1.clean/drivers/atm/horizon.c	Fri Jul  7 06:37:24 2000
+++ linux-2.4.0-test13-pre1.atm-refcount/drivers/atm/horizon.c	Thu Dec 14 12:54:37 2000
@@ -2491,15 +2491,10 @@
     return -EINVAL;
   }
   
-  // prevent module unload while sleeping (kmalloc)
-  // doing this any earlier would complicate more error return paths
-  MOD_INC_USE_COUNT;
-  
   // get space for our vcc stuff and copy parameters into it
   vccp = kmalloc (sizeof(hrz_vcc), GFP_KERNEL);
   if (!vccp) {
     PRINTK (KERN_ERR, "out of memory!");
-    MOD_DEC_USE_COUNT;
     return -ENOMEM;
   }
   *vccp = vcc;
@@ -2531,7 +2526,6 @@
   if (error) {
     PRINTD (DBG_QOS|DBG_VCC, "insufficient cell rate resources");
     kfree (vccp);
-    MOD_DEC_USE_COUNT;
     return error;
   }
   
@@ -2550,7 +2544,6 @@
       error = hrz_open_rx (dev, channel);
     if (error) {
       kfree (vccp);
-      MOD_DEC_USE_COUNT;
       return error;
     }
     // this link allows RX frames through
@@ -2620,7 +2613,6 @@
   kfree (vcc);
   // say the VPI/VCI is free again
   clear_bit(ATM_VF_ADDR,&atm_vcc->flags);
-  MOD_DEC_USE_COUNT;
 }
 
 #if 0
@@ -2751,7 +2743,8 @@
   close:	hrz_close,
   send:		hrz_send,
   sg_send:	hrz_sg_send,
-  proc_read:	hrz_proc_read
+  proc_read:	hrz_proc_read,
+  owner:	THIS_MODULE,
 };
 
 static int __init hrz_probe (void) {
diff -u -r linux-2.4.0-test13-pre1.clean/drivers/atm/iphase.c linux-2.4.0-test13-pre1.atm-refcount/drivers/atm/iphase.c
--- linux-2.4.0-test13-pre1.clean/drivers/atm/iphase.c	Mon Aug  7 07:20:09 2000
+++ linux-2.4.0-test13-pre1.atm-refcount/drivers/atm/iphase.c	Thu Dec 14 12:54:37 2000
@@ -3143,7 +3143,8 @@
 	phy_put:	ia_phy_put,  
 	phy_get:	ia_phy_get,  
 	change_qos:	ia_change_qos,  
-        proc_read:	ia_proc_read
+	proc_read:	ia_proc_read,
+	owner:		THIS_MODULE,
 };  
 	  
   
@@ -3219,7 +3220,6 @@
 		printk(KERN_ERR DEV_LABEL ": no adapter found\n");  
 		return -ENXIO;  
 	}  
-	// MOD_INC_USE_COUNT; 
    	ia_timer.expires = jiffies + 3*HZ;
    	add_timer(&ia_timer); 
    
@@ -3235,7 +3235,6 @@
         int i, j= 0;
  
 	IF_EVENT(printk(">ia cleanup_module\n");)  
-        // MOD_DEC_USE_COUNT;
 	if (MOD_IN_USE)  
 		printk("ia: module in use\n");  
         del_timer(&ia_timer);
diff -u -r linux-2.4.0-test13-pre1.clean/drivers/atm/nicstar.c linux-2.4.0-test13-pre1.atm-refcount/drivers/atm/nicstar.c
--- linux-2.4.0-test13-pre1.clean/drivers/atm/nicstar.c	Tue Nov 14 22:16:33 2000
+++ linux-2.4.0-test13-pre1.atm-refcount/drivers/atm/nicstar.c	Thu Dec 14 12:54:37 2000
@@ -268,7 +268,8 @@
    send:	ns_send,
    phy_put:	ns_phy_put,
    phy_get:	ns_phy_get,
-   proc_read:	ns_proc_read
+   proc_read:	ns_proc_read,
+   owner:	THIS_MODULE,
 };
 static struct timer_list ns_timer;
 static char *mac[NS_MAX_CARDS];
@@ -1633,7 +1634,6 @@
    }
    
    set_bit(ATM_VF_READY,&vcc->flags);
-   MOD_INC_USE_COUNT;
    return 0;
 }
 
@@ -1762,7 +1762,6 @@
    vcc->dev_data = NULL;
    clear_bit(ATM_VF_PARTIAL,&vcc->flags);
    clear_bit(ATM_VF_ADDR,&vcc->flags);
-   MOD_DEC_USE_COUNT;
 
 #ifdef RX_DEBUG
    {
diff -u -r linux-2.4.0-test13-pre1.clean/include/linux/atm_tcp.h linux-2.4.0-test13-pre1.atm-refcount/include/linux/atm_tcp.h
--- linux-2.4.0-test13-pre1.clean/include/linux/atm_tcp.h	Thu Dec 14 13:24:34 2000
+++ linux-2.4.0-test13-pre1.atm-refcount/include/linux/atm_tcp.h	Thu Dec 14 12:59:55 2000
@@ -65,6 +65,7 @@
 	int (*attach)(struct atm_vcc *vcc,int itf);
 	int (*create_persistent)(int itf);
 	int (*remove_persistent)(int itf);
+	struct module *owner;
 };
 
 extern struct atm_tcp_ops atm_tcp_ops;
diff -u -r linux-2.4.0-test13-pre1.clean/include/linux/atmdev.h linux-2.4.0-test13-pre1.atm-refcount/include/linux/atmdev.h
--- linux-2.4.0-test13-pre1.clean/include/linux/atmdev.h	Thu Dec 14 13:24:33 2000
+++ linux-2.4.0-test13-pre1.atm-refcount/include/linux/atmdev.h	Thu Dec 14 12:59:54 2000
@@ -375,6 +375,7 @@
 	void (*free_rx_skb)(struct atm_vcc *vcc, struct sk_buff *skb);
 		/* @@@ temporary hack */
 	int (*proc_read)(struct atm_dev *dev,loff_t *pos,char *page);
+	struct module *owner;
 };
 
 
diff -u -r linux-2.4.0-test13-pre1.clean/net/atm/addr.c linux-2.4.0-test13-pre1.atm-refcount/net/atm/addr.c
--- linux-2.4.0-test13-pre1.clean/net/atm/addr.c	Wed Mar 22 08:38:26 2000
+++ linux-2.4.0-test13-pre1.atm-refcount/net/atm/addr.c	Thu Dec 14 12:54:38 2000
@@ -42,7 +42,7 @@
  */
 
 static DECLARE_MUTEX(local_lock);
-
+extern  spinlock_t atm_dev_lock;
 
 static void notify_sigd(struct atm_dev *dev)
 {
@@ -58,12 +58,14 @@
 	struct atm_dev_addr *this;
 
 	down(&local_lock);
+	spin_lock (&atm_dev_lock);		
 	while (dev->local) {
 		this = dev->local;
 		dev->local = this->next;
 		kfree(this);
 	}
 	up(&local_lock);
+	spin_unlock (&atm_dev_lock);
 	notify_sigd(dev);
 }
 
diff -u -r linux-2.4.0-test13-pre1.clean/net/atm/common.c linux-2.4.0-test13-pre1.atm-refcount/net/atm/common.c
--- linux-2.4.0-test13-pre1.clean/net/atm/common.c	Fri Jul  7 06:37:24 2000
+++ linux-2.4.0-test13-pre1.atm-refcount/net/atm/common.c	Thu Dec 14 12:54:38 2000
@@ -72,6 +72,7 @@
 #define DPRINTK(format,args...)
 #endif
 
+spinlock_t atm_dev_lock = SPIN_LOCK_UNLOCKED;
 
 static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
 {
@@ -139,13 +140,19 @@
 				vcc->dev->ops->free_rx_skb(vcc,skb);
 			else kfree_skb(skb);
 		}
+		spin_lock (&atm_dev_lock);	
+		fops_put (vcc->dev->ops);
 		if (atomic_read(&vcc->rx_inuse))
 			printk(KERN_WARNING "atm_release_vcc: strange ... "
 			    "rx_inuse == %d after closing\n",
 			    atomic_read(&vcc->rx_inuse));
 		bind_vcc(vcc,NULL);
-	}
+	} else
+		spin_lock (&atm_dev_lock);	
+
 	if (free_sk) free_atm_vcc_sk(sk);
+
+	spin_unlock (&atm_dev_lock);
 }
 
 
@@ -238,9 +245,11 @@
 	    vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu);
 	DPRINTK("  RX: %d, PCR %d..%d, SDU %d\n",vcc->qos.rxtp.traffic_class,
 	    vcc->qos.rxtp.min_pcr,vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu);
+	fops_get (dev->ops);
 	if (dev->ops->open) {
 		error = dev->ops->open(vcc,vpi,vci);
 		if (error) {
+			fops_put (dev->ops);
 			bind_vcc(vcc,NULL);
 			return error;
 		}
@@ -252,10 +261,18 @@
 static int atm_do_connect(struct atm_vcc *vcc,int itf,int vpi,int vci)
 {
 	struct atm_dev *dev;
+	int return_val;
 
+	spin_lock (&atm_dev_lock);
 	dev = atm_find_dev(itf);
-	if (!dev) return -ENODEV;
-	return atm_do_connect_dev(vcc,dev,vpi,vci);
+	if (!dev)
+		return_val =  -ENODEV;
+	else
+		return_val = atm_do_connect_dev(vcc,dev,vpi,vci);
+
+	spin_unlock (&atm_dev_lock);
+
+	return return_val;
 }
 
 
@@ -285,8 +302,10 @@
 	else {
 		struct atm_dev *dev;
 
+		spin_lock (&atm_dev_lock);
 		for (dev = atm_devs; dev; dev = dev->next)
 			if (!atm_do_connect_dev(vcc,dev,vpi,vci)) break;
+		spin_unlock (&atm_dev_lock);
 		if (!dev) return -ENODEV;
 	}
 	if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
@@ -523,57 +542,86 @@
 	struct atm_vcc *vcc;
 	int *tmp_buf;
 	void *buf;
-	int error,len,size,number;
+	int error,len,size,number, ret_val;
 
+	ret_val = 0;
+	spin_lock (&atm_dev_lock);
 	vcc = ATM_SD(sock);
 	switch (cmd) {
 		case SIOCOUTQ:
 			if (sock->state != SS_CONNECTED ||
-			    !test_bit(ATM_VF_READY,&vcc->flags))
-				return -EINVAL;
-			return put_user(vcc->sk->sndbuf-
+			    !test_bit(ATM_VF_READY,&vcc->flags)) {
+				ret_val =  -EINVAL;
+				goto done;
+			}
+			ret_val =  put_user(vcc->sk->sndbuf-
 			    atomic_read(&vcc->tx_inuse)-ATM_PDU_OVHD,
 			    (int *) arg) ? -EFAULT : 0;
+			goto done;
 		case SIOCINQ:
 			{
 				struct sk_buff *skb;
 
-				if (sock->state != SS_CONNECTED)
-					return -EINVAL;
+				if (sock->state != SS_CONNECTED) {
+					ret_val = -EINVAL;
+					goto done;
+				}
 				skb = skb_peek(&vcc->recvq);
-				return put_user(skb ? skb->len : 0,(int *) arg)
+				ret_val = put_user(skb ? skb->len : 0,(int *) arg)
 				    ? -EFAULT : 0;
+				goto done;
 			}
 		case ATM_GETNAMES:
 			if (get_user(buf,
-			    &((struct atm_iobuf *) arg)->buffer))
-				return -EFAULT;
+				     &((struct atm_iobuf *) arg)->buffer)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			if (get_user(len,
-			    &((struct atm_iobuf *) arg)->length))
-				return -EFAULT;
+				     &((struct atm_iobuf *) arg)->length)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			size = 0;
 			for (dev = atm_devs; dev; dev = dev->next)
 				size += sizeof(int);
-			if (size > len) return -E2BIG;
+			if (size > len) {
+				ret_val = -E2BIG;
+				goto done;
+			}
 			tmp_buf = kmalloc(size,GFP_KERNEL);
-			if (!tmp_buf) return -ENOMEM;
+			if (!tmp_buf) {
+				ret_val = -ENOMEM;
+				goto done;
+			}
 			for (dev = atm_devs; dev; dev = dev->next)
 				*tmp_buf++ = dev->number;
-			if (copy_to_user(buf,(char *) tmp_buf-size,size))
-				return -EFAULT;
-			return put_user(size,
+			if (copy_to_user(buf,(char *) tmp_buf-size,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
+		        ret_val = put_user(size,
 			    &((struct atm_iobuf *) arg)->length) ? -EFAULT : 0;
+			goto done;
 		case SIOCGSTAMP: /* borrowed from IP */
-			if (!vcc->timestamp.tv_sec) return -ENOENT;
+			if (!vcc->timestamp.tv_sec) {
+				ret_val = -ENOENT;
+				goto done;
+			}
 			vcc->timestamp.tv_sec += vcc->timestamp.tv_usec/1000000;
 			vcc->timestamp.tv_usec %= 1000000;
-			return copy_to_user((void *) arg,&vcc->timestamp,
+			ret_val = copy_to_user((void *) arg,&vcc->timestamp,
 			    sizeof(struct timeval)) ? -EFAULT : 0;
+			goto done;
 		case ATM_SETSC:
 			printk(KERN_WARNING "ATM_SETSC is obsolete\n");
-			return 0;
+			ret_val = 0;
+			goto done;
 		case ATMSIGD_CTRL:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			/*
 			 * The user/kernel protocol for exchanging signalling
 			 * info uses kernel pointers as opaque references,
@@ -581,175 +629,308 @@
 			 * on the kernel... so we should make sure that we
 			 * have the same privledges that /proc/kcore needs
 			 */
-			if (!capable(CAP_SYS_RAWIO)) return -EPERM;
+			if (!capable(CAP_SYS_RAWIO)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			error = sigd_attach(vcc);
 			if (!error) sock->state = SS_CONNECTED;
-			return error;
+			ret_val = error;
+			goto done;
 #ifdef CONFIG_ATM_CLIP
 		case SIOCMKCLIP:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return clip_create(arg);
+			if (!capable(CAP_NET_ADMIN))
+				ret_val = -EPERM;
+			else 
+				ret_val = clip_create(arg);
+			goto done;
 		case ATMARPD_CTRL:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			error = atm_init_atmarp(vcc);
 			if (!error) sock->state = SS_CONNECTED;
-			return error;
+			ret_val = error;
+			goto done;
 		case ATMARP_MKIP:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return clip_mkip(vcc,arg);
+			if (!capable(CAP_NET_ADMIN)) 
+				ret_val = -EPERM;
+			else 
+				ret_val = clip_mkip(vcc,arg);
+			goto done;
 		case ATMARP_SETENTRY:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return clip_setentry(vcc,arg);
+			if (!capable(CAP_NET_ADMIN)) 
+				ret_val = -EPERM;
+			else
+				ret_val = clip_setentry(vcc,arg);
+			goto done;
 		case ATMARP_ENCAP:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return clip_encap(vcc,arg);
+			if (!capable(CAP_NET_ADMIN)) 
+				ret_val = -EPERM;
+			else
+				ret_val = clip_encap(vcc,arg);
+			goto done;
 #endif
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
                 case ATMLEC_CTRL:
-                        if (!capable(CAP_NET_ADMIN)) return -EPERM;
+                        if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
                         if (atm_lane_ops.lecd_attach == NULL)
                                 atm_lane_init();
-                        if (atm_lane_ops.lecd_attach == NULL) /* try again */
-                                return -ENOSYS;
-                        error = atm_lane_ops.lecd_attach(vcc, (int)arg);
-                        if (error >= 0) sock->state = SS_CONNECTED;
-                        return error;
+                        if (atm_lane_ops.lecd_attach == NULL) { /* try again */
+				ret_val = -ENOSYS;
+				goto done;
+			}
+			error = atm_lane_ops.lecd_attach(vcc, (int)arg);
+			if (error >= 0) sock->state = SS_CONNECTED;
+			ret_val =  error;
+			goto done;
                 case ATMLEC_MCAST:
-                        if (!capable(CAP_NET_ADMIN)) return -EPERM;
-                        return atm_lane_ops.mcast_attach(vcc, (int)arg);
+			if (!capable(CAP_NET_ADMIN))
+				ret_val = -EPERM;
+			else
+				ret_val = atm_lane_ops.mcast_attach(vcc, (int)arg);
+			goto done;
                 case ATMLEC_DATA:
-                        if (!capable(CAP_NET_ADMIN)) return -EPERM;
-                        return atm_lane_ops.vcc_attach(vcc, (void*)arg);
+			if (!capable(CAP_NET_ADMIN))
+				ret_val = -EPERM;
+			else
+				ret_val = atm_lane_ops.vcc_attach(vcc, (void*)arg);
+			goto done;
 #endif
 #if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE)
 		case ATMMPC_CTRL:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-                        if (atm_mpoa_ops.mpoad_attach == NULL)
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
+			if (atm_mpoa_ops.mpoad_attach == NULL)
                                 atm_mpoa_init();
-                        if (atm_mpoa_ops.mpoad_attach == NULL) /* try again */
-                                return -ENOSYS;
-                        error = atm_mpoa_ops.mpoad_attach(vcc, (int)arg);
-                        if (error >= 0) sock->state = SS_CONNECTED;
-                        return error;
+			if (atm_mpoa_ops.mpoad_attach == NULL) { /* try again */
+				ret_val = -ENOSYS;
+				goto done;
+			}
+			error = atm_mpoa_ops.mpoad_attach(vcc, (int)arg);
+			if (error >= 0) sock->state = SS_CONNECTED;
+			ret_val = error;
+			goto done;
 		case ATMMPC_DATA:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return atm_mpoa_ops.vcc_attach(vcc, arg);
+			if (!capable(CAP_NET_ADMIN)) 
+				ret_val = -EPERM;
+			else
+				ret_val = atm_mpoa_ops.vcc_attach(vcc, arg);
+			goto done;
 #endif
 #if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE)
 		case SIOCSIFATMTCP:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			if (!atm_tcp_ops.attach) return -ENOPKG;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
+			if (!atm_tcp_ops.attach) {
+				ret_val = -ENOPKG;
+				goto done;
+			}
+			fops_get (&atm_tcp_ops);
 			error = atm_tcp_ops.attach(vcc,(int) arg);
 			if (error >= 0) sock->state = SS_CONNECTED;
-			return error;
+			else            fops_put (&atm_tcp_ops);
+			ret_val = error;
+			goto done;
 		case ATMTCP_CREATE:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			if (!atm_tcp_ops.create_persistent) return -ENOPKG;
-			return atm_tcp_ops.create_persistent((int) arg);
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
+			if (!atm_tcp_ops.create_persistent) {
+				ret_val = -ENOPKG;
+				goto done;
+			}
+			error = atm_tcp_ops.create_persistent((int) arg);
+			if (error < 0) fops_put (&atm_tcp_ops);
+			ret_val = error;
+			goto done;
 		case ATMTCP_REMOVE:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			if (!atm_tcp_ops.remove_persistent) return -ENOPKG;
-			return atm_tcp_ops.remove_persistent((int) arg);
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
+			if (!atm_tcp_ops.remove_persistent) {
+				ret_val = -ENOPKG;
+				goto done;
+			}
+			error = atm_tcp_ops.remove_persistent((int) arg);
+			fops_put (&atm_tcp_ops);
+			ret_val = error;
+			goto done;
 #endif
 		default:
 			break;
 	}
-	if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) return -EFAULT;
-	if (get_user(len,&((struct atmif_sioc *) arg)->length)) return -EFAULT;
-	if (get_user(number,&((struct atmif_sioc *) arg)->number))
-		return -EFAULT;
-	if (!(dev = atm_find_dev(number))) return -ENODEV;
+	if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) {
+		ret_val = -EFAULT;
+		goto done;
+	}
+	if (get_user(len,&((struct atmif_sioc *) arg)->length)) {
+		ret_val = -EFAULT;
+		goto done;
+	}
+	if (get_user(number,&((struct atmif_sioc *) arg)->number)) {
+		ret_val = -EFAULT;
+		goto done;
+	}
+	if (!(dev = atm_find_dev(number))) {
+		ret_val = -ENODEV;
+		goto done;
+	}
+	
 	size = 0;
 	switch (cmd) {
 		case ATM_GETTYPE:
 			size = strlen(dev->type)+1;
-			if (copy_to_user(buf,dev->type,size)) return -EFAULT;
+			if (copy_to_user(buf,dev->type,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			break;
 		case ATM_GETESI:
 			size = ESI_LEN;
-			if (copy_to_user(buf,dev->esi,size)) return -EFAULT;
+			if (copy_to_user(buf,dev->esi,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			break;
 		case ATM_SETESI:
 			{
 				int i;
 
 				for (i = 0; i < ESI_LEN; i++)
-					if (dev->esi[i]) return -EEXIST;
+					if (dev->esi[i]) {
+						ret_val = -EEXIST;
+						goto done;
+					}
 			}
 			/* fall through */
 		case ATM_SETESIF:
 			{
 				unsigned char esi[ESI_LEN];
 
-				if (!capable(CAP_NET_ADMIN)) return -EPERM;
-				if (copy_from_user(esi,buf,ESI_LEN))
-					return -EFAULT;
+				if (!capable(CAP_NET_ADMIN)) {
+					ret_val = -EPERM;
+					goto done;
+				}
+				if (copy_from_user(esi,buf,ESI_LEN)) {
+					ret_val = -EFAULT;
+					goto done;
+				}
 				memcpy(dev->esi,esi,ESI_LEN);
-				return ESI_LEN;
+				ret_val =  ESI_LEN;
+				goto done;
 			}
 		case ATM_GETSTATZ:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			/* fall through */
 		case ATM_GETSTAT:
 			size = sizeof(struct atm_dev_stats);
 			error = fetch_stats(dev,buf,cmd == ATM_GETSTATZ);
-			if (error) return error;
+			if (error) {
+				ret_val = error;
+				goto done;
+			}
 			break;
 		case ATM_GETCIRANGE:
 			size = sizeof(struct atm_cirange);
-			if (copy_to_user(buf,&dev->ci_range,size))
-				return -EFAULT;
+			if (copy_to_user(buf,&dev->ci_range,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			break;
 		case ATM_GETLINKRATE:
 			size = sizeof(int);
-			if (copy_to_user(buf,&dev->link_rate,size))
-				return -EFAULT;
+			if (copy_to_user(buf,&dev->link_rate,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			break;
 		case ATM_RSTADDR:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			reset_addr(dev);
 			break;
 		case ATM_ADDADDR:
 		case ATM_DELADDR:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			{
 				struct sockaddr_atmsvc addr;
 
-				if (copy_from_user(&addr,buf,sizeof(addr)))
-					return -EFAULT;
+				if (copy_from_user(&addr,buf,sizeof(addr))) {
+					ret_val = -EFAULT;
+					goto done;
+				}
 				if (cmd == ATM_ADDADDR)
-					return add_addr(dev,&addr);
-				else return del_addr(dev,&addr);
+					ret_val = add_addr(dev,&addr);
+				else
+					ret_val = del_addr(dev,&addr);
+				goto done;
 			}
 		case ATM_GETADDR:
 			size = get_addr(dev,buf,len);
-			if (size < 0) return size;
+			if (size < 0)
+				ret_val = size;
+			else
 			/* may return 0, but later on size == 0 means "don't
 			   write the length" */
-			return put_user(size,
-			    &((struct atmif_sioc *) arg)->length) ? -EFAULT : 0;
+				ret_val = put_user(size,
+						   &((struct atmif_sioc *) arg)->length) ? -EFAULT : 0;
+			goto done;
 		case ATM_SETLOOP:
 			if (__ATM_LM_XTRMT((int) (long) buf) &&
 			    __ATM_LM_XTLOC((int) (long) buf) >
-			    __ATM_LM_XTRMT((int) (long) buf))
-				return -EINVAL;
+			    __ATM_LM_XTRMT((int) (long) buf)) {
+				ret_val = -EINVAL;
+				goto done;
+			}
 			/* fall through */
 		case ATM_SETCIRANGE:
 		case SONET_GETSTATZ:
 		case SONET_SETDIAG:
 		case SONET_CLRDIAG:
 		case SONET_SETFRAMING:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			/* fall through */
 		default:
-			if (!dev->ops->ioctl) return -EINVAL;
+			if (!dev->ops->ioctl) {
+				ret_val = -EINVAL;
+				goto done;
+			}
 			size = dev->ops->ioctl(dev,cmd,buf);
-			if (size < 0)
-				return size == -ENOIOCTLCMD ? -EINVAL : size;
+			if (size < 0) {
+				ret_val = (size == -ENOIOCTLCMD ? -EINVAL : size);
+				goto done;
+			}
 	}
-	if (!size) return 0;
-	return put_user(size,&((struct atmif_sioc *) arg)->length) ?
-	    -EFAULT : 0;
+	
+	if (size)
+		ret_val =  put_user(size,&((struct atmif_sioc *) arg)->length) ?
+			-EFAULT : 0;
+
+ done:
+	spin_unlock (&atm_dev_lock); 
+	return ret_val;
 }
 
 
diff -u -r linux-2.4.0-test13-pre1.clean/net/atm/resources.c linux-2.4.0-test13-pre1.atm-refcount/net/atm/resources.c
--- linux-2.4.0-test13-pre1.clean/net/atm/resources.c	Wed Mar 22 08:38:26 2000
+++ linux-2.4.0-test13-pre1.atm-refcount/net/atm/resources.c	Thu Dec 14 12:54:38 2000
@@ -25,6 +25,7 @@
 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;
 
 
 static struct atm_dev *alloc_atm_dev(const char *type)
@@ -48,11 +49,15 @@
 
 static void free_atm_dev(struct atm_dev *dev)
 {
+	spin_lock (&atm_dev_lock);
+	
 	if (dev->prev) dev->prev->next = dev->next;
 	else atm_devs = dev->next;
 	if (dev->next) dev->next->prev = dev->prev;
 	else last_dev = dev->prev;
 	kfree(dev);
+	
+	spin_unlock (&atm_dev_lock);
 }
 
 
@@ -100,10 +105,12 @@
 		if (atm_proc_dev_register(dev) < 0) {
 			printk(KERN_ERR "atm_dev_register: "
 			    "atm_proc_dev_register failed for dev %s\n",type);
+			spin_unlock (&atm_dev_lock);		
 			free_atm_dev(dev);
 			return NULL;
 		}
 #endif
+	spin_unlock (&atm_dev_lock);		
 	return dev;
 }
 
diff -u -r linux-2.4.0-test13-pre1.clean/net/atm/signaling.c linux-2.4.0-test13-pre1.atm-refcount/net/atm/signaling.c
--- linux-2.4.0-test13-pre1.clean/net/atm/signaling.c	Wed Nov 15 08:36:01 2000
+++ linux-2.4.0-test13-pre1.atm-refcount/net/atm/signaling.c	Thu Dec 14 12:54:38 2000
@@ -33,6 +33,7 @@
 struct atm_vcc *sigd = NULL;
 static DECLARE_WAIT_QUEUE_HEAD(sigd_sleep);
 
+extern spinlock_t atm_dev_lock;
 
 static void sigd_put_skb(struct sk_buff *skb)
 {
@@ -219,7 +220,10 @@
 		printk(KERN_ERR "sigd_close: closing with requests pending\n");
 	while ((skb = skb_dequeue(&vcc->recvq))) kfree_skb(skb);
 	purge_vccs(nodev_vccs);
+
+	spin_lock (&atm_dev_lock);
 	for (dev = atm_devs; dev; dev = dev->next) purge_vccs(dev->vccs);
+	spin_unlock (&atm_dev_lock);
 }
 
 







-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2000-12-15 12:34 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2000-11-22  9:31 [PATCH] atmrefcount Patrick van de Lageweg
2000-11-22 16:03 ` Mitchell Blank Jr
  -- strict thread matches above, loose matches on Subject: below --
2000-11-29  8:57 Patrick van de Lageweg
2000-11-29  8:58 Patrick van de Lageweg
2000-12-12 15:44 Patrick van de Lageweg
2000-12-15 12:03 Patrick van de Lageweg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox