netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH][ATM][3/3] assorted changes for atm
@ 2003-06-17 12:40 chas williams
  2003-06-17 17:31 ` David S. Miller
  0 siblings, 1 reply; 5+ messages in thread
From: chas williams @ 2003-06-17 12:40 UTC (permalink / raw)
  To: davem; +Cc: netdev


[atm]: keep vcc's on global list instead of per device

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.1403  -> 1.1404 
#	    drivers/atm/he.c	1.12    -> 1.13   
#	  net/atm/atm_misc.c	1.4     -> 1.5    
#	   drivers/atm/eni.c	1.14    -> 1.15   
#	      net/atm/proc.c	1.17    -> 1.18   
#	       net/atm/pvc.c	1.13    -> 1.14   
#	drivers/atm/idt77252.c	1.14    -> 1.15   
#	       net/atm/lec.c	1.26    -> 1.27   
#	       net/atm/svc.c	1.15    -> 1.16   
#	drivers/atm/atmtcp.c	1.7     -> 1.8    
#	    net/atm/common.h	1.9     -> 1.10   
#	 net/atm/signaling.c	1.11    -> 1.12   
#	 net/atm/resources.h	1.4     -> 1.5    
#	       net/atm/mpc.c	1.17    -> 1.18   
#	include/linux/atmdev.h	1.15    -> 1.16   
#	 net/atm/resources.c	1.10    -> 1.11   
#	      net/atm/clip.c	1.14    -> 1.15   
#	drivers/atm/fore200e.c	1.15    -> 1.16   
#	    net/atm/common.c	1.32    -> 1.33   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/06/17	chas@relax.cmf.nrl.navy.mil	1.1404
# vcc_sklist conversion
# --------------------------------------------
#
diff -Nru a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c
--- a/drivers/atm/atmtcp.c	Tue Jun 17 08:26:40 2003
+++ b/drivers/atm/atmtcp.c	Tue Jun 17 08:26:40 2003
@@ -153,9 +153,9 @@
 
 static int atmtcp_v_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
 {
-	unsigned long flags;
 	struct atm_cirange ci;
 	struct atm_vcc *vcc;
+	struct sock *s;
 
 	if (cmd != ATM_SETCIRANGE) return -ENOIOCTLCMD;
 	if (copy_from_user(&ci,(void *) arg,sizeof(ci))) return -EFAULT;
@@ -163,14 +163,18 @@
 	if (ci.vci_bits == ATM_CI_MAX) ci.vci_bits = MAX_VCI_BITS;
 	if (ci.vpi_bits > MAX_VPI_BITS || ci.vpi_bits < 0 ||
 	    ci.vci_bits > MAX_VCI_BITS || ci.vci_bits < 0) return -EINVAL;
-	spin_lock_irqsave(&dev->lock, flags);
-	for (vcc = dev->vccs; vcc; vcc = vcc->next)
+	read_lock(&vcc_sklist_lock);
+	for (s = vcc_sklist; s; s = s->sk_next) {
+		vcc = atm_sk(s);
+		if (vcc->dev != dev)
+			continue;
 		if ((vcc->vpi >> ci.vpi_bits) ||
 		    (vcc->vci >> ci.vci_bits)) {
-			spin_unlock_irqrestore(&dev->lock, flags);
+			read_unlock(&vcc_sklist_lock);
 			return -EBUSY;
 		}
-	spin_unlock_irqrestore(&dev->lock, flags);
+	}
+	read_unlock(&vcc_sklist_lock);
 	dev->ci_range = ci;
 	return 0;
 }
@@ -233,9 +237,9 @@
 
 static void atmtcp_c_close(struct atm_vcc *vcc)
 {
-	unsigned long flags;
 	struct atm_dev *atmtcp_dev;
 	struct atmtcp_dev_data *dev_data;
+	struct sock *s;
 	struct atm_vcc *walk;
 
 	atmtcp_dev = (struct atm_dev *) vcc->dev_data;
@@ -246,19 +250,23 @@
 	kfree(dev_data);
 	shutdown_atm_dev(atmtcp_dev);
 	vcc->dev_data = NULL;
-	spin_lock_irqsave(&atmtcp_dev->lock, flags);
-	for (walk = atmtcp_dev->vccs; walk; walk = walk->next)
+	read_lock(&vcc_sklist_lock);
+	for (s = vcc_sklist; s; s = s->sk_next) {
+		walk = atm_sk(s);
+		if (walk->dev != atmtcp_dev)
+			continue;
 		wake_up(&walk->sleep);
-	spin_unlock_irqrestore(&atmtcp_dev->lock, flags);
+	}
+	read_unlock(&vcc_sklist_lock);
 }
 
 
 static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb)
 {
-	unsigned long flags;
 	struct atm_dev *dev;
 	struct atmtcp_hdr *hdr;
-	struct atm_vcc *out_vcc;
+	struct sock *s;
+	struct atm_vcc *out_vcc = NULL;
 	struct sk_buff *new_skb;
 	int result = 0;
 
@@ -270,13 +278,17 @@
 		    (struct atmtcp_control *) skb->data);
 		goto done;
 	}
-	spin_lock_irqsave(&dev->lock, flags);
-	for (out_vcc = dev->vccs; out_vcc; out_vcc = out_vcc->next)
+	read_lock(&vcc_sklist_lock);
+	for (s = vcc_sklist; s; s = s->sk_next) {
+		out_vcc = atm_sk(s);
+		if (out_vcc->dev != dev)
+			continue;
 		if (out_vcc->vpi == ntohs(hdr->vpi) &&
 		    out_vcc->vci == ntohs(hdr->vci) &&
 		    out_vcc->qos.rxtp.traffic_class != ATM_NONE)
 			break;
-	spin_unlock_irqrestore(&dev->lock, flags);
+	}
+	read_unlock(&vcc_sklist_lock);
 	if (!out_vcc) {
 		atomic_inc(&vcc->stats->tx_err);
 		goto done;
@@ -366,7 +378,7 @@
 	if (itf != -1) dev = atm_dev_lookup(itf);
 	if (dev) {
 		if (dev->ops != &atmtcp_v_dev_ops) {
-			atm_dev_release(dev);
+			atm_dev_put(dev);
 			return -EMEDIUMTYPE;
 		}
 		if (PRIV(dev)->vcc) return -EBUSY;
@@ -378,7 +390,8 @@
 		if (error) return error;
 	}
 	PRIV(dev)->vcc = vcc;
-	bind_vcc(vcc,&atmtcp_control_dev);
+	vcc->dev = &atmtcp_control_dev;
+	vcc_insert_socket(vcc->sk);
 	set_bit(ATM_VF_META,&vcc->flags);
 	set_bit(ATM_VF_READY,&vcc->flags);
 	vcc->dev_data = dev;
@@ -402,7 +415,7 @@
 	dev = atm_dev_lookup(itf);
 	if (!dev) return -ENODEV;
 	if (dev->ops != &atmtcp_v_dev_ops) {
-		atm_dev_release(dev);
+		atm_dev_put(dev);
 		return -EMEDIUMTYPE;
 	}
 	dev_data = PRIV(dev);
@@ -410,7 +423,7 @@
 	dev_data->persist = 0;
 	if (PRIV(dev)->vcc) return 0;
 	kfree(dev_data);
-	atm_dev_release(dev);
+	atm_dev_put(dev);
 	shutdown_atm_dev(dev);
 	return 0;
 }
diff -Nru a/drivers/atm/eni.c b/drivers/atm/eni.c
--- a/drivers/atm/eni.c	Tue Jun 17 08:26:40 2003
+++ b/drivers/atm/eni.c	Tue Jun 17 08:26:40 2003
@@ -1887,10 +1887,10 @@
 
 static int get_ci(struct atm_vcc *vcc,short *vpi,int *vci)
 {
-	unsigned long flags;
+	struct sock *s;
 	struct atm_vcc *walk;
 
-	spin_lock_irqsave(&vcc->dev->lock, flags);
+	read_lock(&vcc_sklist_lock);
 	if (*vpi == ATM_VPI_ANY) *vpi = 0;
 	if (*vci == ATM_VCI_ANY) {
 		for (*vci = ATM_NOT_RSV_VCI; *vci < NR_VCI; (*vci)++) {
@@ -1898,40 +1898,47 @@
 			    ENI_DEV(vcc->dev)->rx_map[*vci])
 				continue;
 			if (vcc->qos.txtp.traffic_class != ATM_NONE) {
-				for (walk = vcc->dev->vccs; walk;
-				    walk = walk->next)
+				for (s = vcc_sklist; s; s = s->sk_next) {
+					walk = atm_sk(s);
+					if (walk->dev != vcc->dev)
+						continue;
 					if (test_bit(ATM_VF_ADDR,&walk->flags)
 					    && walk->vci == *vci &&
 					    walk->qos.txtp.traffic_class !=
 					    ATM_NONE)
 						break;
-				if (walk) continue;
+				}
+				if (s) continue;
 			}
 			break;
 		}
-		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		read_unlock(&vcc_sklist_lock);
 		return *vci == NR_VCI ? -EADDRINUSE : 0;
 	}
 	if (*vci == ATM_VCI_UNSPEC) {
-		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		read_unlock(&vcc_sklist_lock);
 		return 0;
 	}
 	if (vcc->qos.rxtp.traffic_class != ATM_NONE &&
 	    ENI_DEV(vcc->dev)->rx_map[*vci]) {
-		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		read_unlock(&vcc_sklist_lock);
 		return -EADDRINUSE;
 	}
 	if (vcc->qos.txtp.traffic_class == ATM_NONE) {
-		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		read_unlock(&vcc_sklist_lock);
 		return 0;
 	}
-	for (walk = vcc->dev->vccs; walk; walk = walk->next)
+	for (s = vcc_sklist; s; s = s->sk_next) {
+		walk = atm_sk(s);
+		if (walk->dev != vcc->dev)
+			continue;
 		if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vci == *vci &&
 		    walk->qos.txtp.traffic_class != ATM_NONE) {
-			spin_unlock_irqrestore(&vcc->dev->lock, flags);
+			read_unlock(&vcc_sklist_lock);
 			return -EADDRINUSE;
 		}
-	spin_unlock_irqrestore(&vcc->dev->lock, flags);
+	}
+	read_unlock(&vcc_sklist_lock);
 	return 0;
 }
 
@@ -2139,7 +2146,7 @@
 
 static int eni_proc_read(struct atm_dev *dev,loff_t *pos,char *page)
 {
-	unsigned long flags;
+	struct sock *s;
 	static const char *signal[] = { "LOST","unknown","okay" };
 	struct eni_dev *eni_dev = ENI_DEV(dev);
 	struct atm_vcc *vcc;
@@ -2212,11 +2219,15 @@
 		return sprintf(page,"%10sbacklog %u packets\n","",
 		    skb_queue_len(&tx->backlog));
 	}
-	spin_lock_irqsave(&dev->lock, flags);
-	for (vcc = dev->vccs; vcc; vcc = vcc->next) {
-		struct eni_vcc *eni_vcc = ENI_VCC(vcc);
+	read_lock(&vcc_sklist_lock);
+	for (s = vcc_sklist; s; s = s->sk_next) {
+		struct eni_vcc *eni_vcc;
 		int length;
 
+		vcc = atm_sk(s);
+		if (vcc->dev != dev)
+			continue;
+		eni_vcc = ENI_VCC(vcc);
 		if (--left) continue;
 		length = sprintf(page,"vcc %4d: ",vcc->vci);
 		if (eni_vcc->rx) {
@@ -2231,10 +2242,10 @@
 			length += sprintf(page+length,"tx[%d], txing %d bytes",
 			    eni_vcc->tx->index,eni_vcc->txing);
 		page[length] = '\n';
-		spin_unlock_irqrestore(&dev->lock, flags);
+		read_unlock(&vcc_sklist_lock);
 		return length+1;
 	}
-	spin_unlock_irqrestore(&dev->lock, flags);
+	read_unlock(&vcc_sklist_lock);
 	for (i = 0; i < eni_dev->free_len; i++) {
 		struct eni_free *fe = eni_dev->free_list+i;
 		unsigned long offset;
diff -Nru a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
--- a/drivers/atm/fore200e.c	Tue Jun 17 08:26:40 2003
+++ b/drivers/atm/fore200e.c	Tue Jun 17 08:26:40 2003
@@ -1069,18 +1069,22 @@
 static struct atm_vcc* 
 fore200e_find_vcc(struct fore200e* fore200e, struct rpd* rpd)
 {
-    unsigned long flags;
+    struct sock *s;
     struct atm_vcc* vcc;
 
-    spin_lock_irqsave(&fore200e->atm_dev->lock, flags);
-    for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) {
-
-	if (vcc->vpi == rpd->atm_header.vpi && vcc->vci == rpd->atm_header.vci)
-	    break;
+    read_lock(&vcc_sklist_lock);
+    for(s = vcc_sklist; s; s = s->sk_next) {
+	vcc = atm_sk(s);
+	if (vcc->dev != fore200e->atm_dev)
+		continue;
+	if (vcc->vpi == rpd->atm_header.vpi && vcc->vci == rpd->atm_header.vci) {
+            read_unlock(&vcc_sklist_lock);
+	    return vcc;
+	}
     }
-    spin_unlock_irqrestore(&fore200e->atm_dev->lock, flags);
-    
-    return vcc;
+    read_unlock(&vcc_sklist_lock);
+
+    return NULL;
 }
 
 
@@ -1350,20 +1354,23 @@
 static int
 fore200e_walk_vccs(struct atm_vcc *vcc, short *vpi, int *vci)
 {
-    unsigned long flags;
     struct atm_vcc* walk;
+    struct sock *s;
 
     /* find a free VPI */
 
-    spin_lock_irqsave(&vcc->dev->lock, flags);
+    read_lock(&vcc_sklist_lock);
 
     if (*vpi == ATM_VPI_ANY) {
 
-	for (*vpi = 0, walk = vcc->dev->vccs; walk; walk = walk->next) {
+	for (*vpi = 0, s = vcc_sklist; s; s = s->sk_next) {
+	    walk = atm_sk(s);
+	    if (walk->dev != vcc->dev)
+		continue;
 
 	    if ((walk->vci == *vci) && (walk->vpi == *vpi)) {
 		(*vpi)++;
-		walk = vcc->dev->vccs;
+		s = vcc_sklist;
 	    }
 	}
     }
@@ -1371,16 +1378,19 @@
     /* find a free VCI */
     if (*vci == ATM_VCI_ANY) {
 	
-	for (*vci = ATM_NOT_RSV_VCI, walk = vcc->dev->vccs; walk; walk = walk->next) {
+	for (*vci = ATM_NOT_RSV_VCI, s = vcc_sklist; s; s = s->sk_next) {
+	    walk = atm_sk(s);
+	    if (walk->dev != vcc->dev)
+		continue;
 
 	    if ((walk->vpi = *vpi) && (walk->vci == *vci)) {
 		*vci = walk->vci + 1;
-		walk = vcc->dev->vccs;
+		s = vcc_sklist;
 	    }
 	}
     }
 
-    spin_unlock_irqrestore(&vcc->dev->lock, flags);
+    read_unlock(&vcc_sklist_lock);
 
     return 0;
 }
@@ -2642,7 +2652,7 @@
 static int
 fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page)
 {
-    unsigned long flags;
+    struct sock *s;
     struct fore200e* fore200e  = FORE200E_DEV(dev);
     int              len, left = *pos;
 
@@ -2889,8 +2899,12 @@
 	len = sprintf(page,"\n"    
 		      " VCCs:\n  address\tVPI.VCI:AAL\t(min/max tx PDU size) (min/max rx PDU size)\n");
 	
-	spin_lock_irqsave(&fore200e->atm_dev->lock, flags);
-	for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) {
+	read_lock(&vcc_sklist_lock);
+	for (s = vcc_sklist; s; s = s->sk_next) {
+	    vcc = atm_sk(s);
+
+	    if (vcc->dev != fore200e->atm_dev)
+		    continue;
 
 	    fore200e_vcc = FORE200E_VCC(vcc);
 	    
@@ -2904,7 +2918,7 @@
 			   fore200e_vcc->rx_max_pdu
 		);
 	}
-	spin_unlock_irqrestore(&fore200e->atm_dev->lock, flags);
+	read_unlock(&vcc_sklist_lock);
 
 	return len;
     }
diff -Nru a/drivers/atm/he.c b/drivers/atm/he.c
--- a/drivers/atm/he.c	Tue Jun 17 08:26:40 2003
+++ b/drivers/atm/he.c	Tue Jun 17 08:26:40 2003
@@ -79,7 +79,6 @@
 #include <linux/sonet.h>
 
 #define USE_TASKLET
-#define USE_HE_FIND_VCC
 #undef USE_SCATTERGATHER
 #undef USE_CHECKSUM_HW			/* still confused about this */
 #define USE_RBPS
@@ -328,25 +327,24 @@
 		he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 7)
 
 static __inline__ struct atm_vcc*
-he_find_vcc(struct he_dev *he_dev, unsigned cid)
+__find_vcc(struct he_dev *he_dev, unsigned cid)
 {
-	unsigned long flags;
 	struct atm_vcc *vcc;
+	struct sock *s;
 	short vpi;
 	int vci;
 
 	vpi = cid >> he_dev->vcibits;
 	vci = cid & ((1 << he_dev->vcibits) - 1);
 
-	spin_lock_irqsave(&he_dev->atm_dev->lock, flags);
-	for (vcc = he_dev->atm_dev->vccs; vcc; vcc = vcc->next)
-		if (vcc->vci == vci && vcc->vpi == vpi
-			&& vcc->qos.rxtp.traffic_class != ATM_NONE) {
-				spin_unlock_irqrestore(&he_dev->atm_dev->lock, flags);
+	for (s = vcc_sklist; s; s = s->sk_next) {
+		vcc = atm_sk(s);
+		if (vcc->dev == he_dev->atm_dev &&
+		    vcc->vci == vci && vcc->vpi == vpi &&
+		    vcc->qos.rxtp.traffic_class != ATM_NONE) {
 				return vcc;
-			}
-
-	spin_unlock_irqrestore(&he_dev->atm_dev->lock, flags);
+		}
+	}
 	return NULL;
 }
 
@@ -1566,17 +1564,6 @@
 	reg |= RX_ENABLE;
 	he_writel(he_dev, reg, RC_CONFIG);
 
-#ifndef USE_HE_FIND_VCC
-	he_dev->he_vcc_table = kmalloc(sizeof(struct he_vcc_table) * 
-			(1 << (he_dev->vcibits + he_dev->vpibits)), GFP_KERNEL);
-	if (he_dev->he_vcc_table == NULL) {
-		hprintk("failed to alloc he_vcc_table\n");
-		return -ENOMEM;
-	}
-	memset(he_dev->he_vcc_table, 0, sizeof(struct he_vcc_table) *
-				(1 << (he_dev->vcibits + he_dev->vpibits)));
-#endif
-
 	for (i = 0; i < HE_NUM_CS_STPER; ++i) {
 		he_dev->cs_stper[i].inuse = 0;
 		he_dev->cs_stper[i].pcr = -1;
@@ -1712,11 +1699,6 @@
 							he_dev->tpd_base, he_dev->tpd_base_phys);
 #endif
 
-#ifndef USE_HE_FIND_VCC
-	if (he_dev->he_vcc_table)
-		kfree(he_dev->he_vcc_table);
-#endif
-
 	if (he_dev->pci_dev) {
 		pci_read_config_word(he_dev->pci_dev, PCI_COMMAND, &command);
 		command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
@@ -1798,6 +1780,7 @@
 	int pdus_assembled = 0;
 	int updated = 0;
 
+	read_lock(&vcc_sklist_lock);
 	while (he_dev->rbrq_head != rbrq_tail) {
 		++updated;
 
@@ -1823,13 +1806,10 @@
 		buf_len = RBRQ_BUFLEN(he_dev->rbrq_head) * 4;
 		cid = RBRQ_CID(he_dev->rbrq_head);
 
-#ifdef USE_HE_FIND_VCC
 		if (cid != lastcid)
-			vcc = he_find_vcc(he_dev, cid);
+			vcc = __find_vcc(he_dev, cid);
 		lastcid = cid;
-#else
-		vcc = HE_LOOKUP_VCC(he_dev, cid);
-#endif
+
 		if (vcc == NULL) {
 			hprintk("vcc == NULL  (cid 0x%x)\n", cid);
 			if (!RBRQ_HBUF_ERR(he_dev->rbrq_head))
@@ -1966,6 +1946,7 @@
 					RBRQ_MASK(++he_dev->rbrq_head));
 
 	}
+	read_unlock(&vcc_sklist_lock);
 
 	if (updated) {
 		if (updated > he_dev->rbrq_peak)
@@ -2565,10 +2546,6 @@
 #endif
 
 		spin_unlock_irqrestore(&he_dev->global_lock, flags);
-
-#ifndef USE_HE_FIND_VCC
-		HE_LOOKUP_VCC(he_dev, cid) = vcc;
-#endif
 	}
 
 open_failed:
@@ -2634,9 +2611,6 @@
 		if (timeout == 0)
 			hprintk("close rx timeout cid 0x%x\n", cid);
 
-#ifndef USE_HE_FIND_VCC
-		HE_LOOKUP_VCC(he_dev, cid) = NULL;
-#endif
 		HPRINTK("close rx cid 0x%x complete\n", cid);
 
 	}
diff -Nru a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
--- a/drivers/atm/idt77252.c	Tue Jun 17 08:26:40 2003
+++ b/drivers/atm/idt77252.c	Tue Jun 17 08:26:40 2003
@@ -2403,37 +2403,43 @@
 static int
 idt77252_find_vcc(struct atm_vcc *vcc, short *vpi, int *vci)
 {
-	unsigned long flags;
+	struct sock *s;
 	struct atm_vcc *walk;
 
-	spin_lock_irqsave(&vcc->dev->lock, flags);
+	read_lock(&vcc_sklist_lock);
 	if (*vpi == ATM_VPI_ANY) {
 		*vpi = 0;
-		walk = vcc->dev->vccs;
-		while (walk) {
+		s = vcc_sklist;
+		while (s) {
+			walk = atm_sk(s);
+			if (walk->dev != vcc->dev)
+				continue;
 			if ((walk->vci == *vci) && (walk->vpi == *vpi)) {
 				(*vpi)++;
-				walk = vcc->dev->vccs;
+				s = vcc_sklist;
 				continue;
 			}
-			walk = walk->next;
+			s = s->sk_next;
 		}
 	}
 
 	if (*vci == ATM_VCI_ANY) {
 		*vci = ATM_NOT_RSV_VCI;
-		walk = vcc->dev->vccs;
-		while (walk) {
+		s = vcc_sklist;
+		while (s) {
+			walk = atm_sk(s);
+			if (walk->dev != vcc->dev)
+				continue;
 			if ((walk->vci == *vci) && (walk->vpi == *vpi)) {
 				(*vci)++;
-				walk = vcc->dev->vccs;
+				s = vcc_sklist;
 				continue;
 			}
-			walk = walk->next;
+			s = s->sk_next;
 		}
 	}
 
-	spin_unlock_irqrestore(&vcc->dev->lock, flags);
+	read_unlock(&vcc_sklist_lock);
 	return 0;
 }
 
diff -Nru a/include/linux/atmdev.h b/include/linux/atmdev.h
--- a/include/linux/atmdev.h	Tue Jun 17 08:26:40 2003
+++ b/include/linux/atmdev.h	Tue Jun 17 08:26:40 2003
@@ -293,7 +293,6 @@
 	struct k_atm_aal_stats *stats;	/* pointer to AAL stats group */
 	wait_queue_head_t sleep;	/* if socket is busy */
 	struct sock	*sk;		/* socket backpointer */
-	struct atm_vcc	*prev,*next;
 	/* SVC part --- may move later ------------------------------------- */
 	short		itf;		/* interface number */
 	struct sockaddr_atmsvc local;
@@ -320,8 +319,6 @@
 					/* (NULL) */
 	const char	*type;		/* device type name */
 	int		number;		/* device index */
-	struct atm_vcc	*vccs;		/* VCC table (or NULL) */
-	struct atm_vcc	*last;		/* last VCC (or undefined) */
 	void		*dev_data;	/* per-device data */
 	void		*phy_data;	/* private PHY date */
 	unsigned long	flags;		/* device flags (ATM_DF_*) */
@@ -390,6 +387,9 @@
 	unsigned long	atm_options;	/* ATM layer options */
 };
 
+extern struct sock *vcc_sklist;
+extern rwlock_t vcc_sklist_lock;
+
 #define ATM_SKB(skb) (((struct atm_skb_data *) (skb)->cb))
 
 struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
@@ -397,7 +397,8 @@
 struct atm_dev *atm_dev_lookup(int number);
 void atm_dev_deregister(struct atm_dev *dev);
 void shutdown_atm_dev(struct atm_dev *dev);
-void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev);
+void vcc_insert_socket(struct sock *sk);
+void vcc_remove_socket(struct sock *sk);
 
 
 /*
@@ -436,7 +437,7 @@
 }
 
 
-static inline void atm_dev_release(struct atm_dev *dev)
+static inline void atm_dev_put(struct atm_dev *dev)
 {
 	atomic_dec(&dev->refcnt);
 
diff -Nru a/net/atm/atm_misc.c b/net/atm/atm_misc.c
--- a/net/atm/atm_misc.c	Tue Jun 17 08:26:40 2003
+++ b/net/atm/atm_misc.c	Tue Jun 17 08:26:40 2003
@@ -47,15 +47,20 @@
 
 static int check_ci(struct atm_vcc *vcc,short vpi,int vci)
 {
+	struct sock *s;
 	struct atm_vcc *walk;
 
-	for (walk = vcc->dev->vccs; walk; walk = walk->next)
+	for (s = vcc_sklist; s; s = s->sk_next) {
+		walk = atm_sk(s);
+		if (walk->dev != vcc->dev)
+			continue;
 		if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vpi == vpi &&
 		    walk->vci == vci && ((walk->qos.txtp.traffic_class !=
 		    ATM_NONE && vcc->qos.txtp.traffic_class != ATM_NONE) ||
 		    (walk->qos.rxtp.traffic_class != ATM_NONE &&
 		    vcc->qos.rxtp.traffic_class != ATM_NONE)))
 			return -EADDRINUSE;
+	}
 		/* allow VCCs with same VPI/VCI iff they don't collide on
 		   TX/RX (but we may refuse such sharing for other reasons,
 		   e.g. if protocol requires to have both channels) */
@@ -65,17 +70,16 @@
 
 int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci)
 {
-	unsigned long flags;
 	static short p = 0; /* poor man's per-device cache */
 	static int c = 0;
 	short old_p;
 	int old_c;
 	int err;
 
-	spin_lock_irqsave(&vcc->dev->lock, flags);
+	read_lock(&vcc_sklist_lock);
 	if (*vpi != ATM_VPI_ANY && *vci != ATM_VCI_ANY) {
 		err = check_ci(vcc,*vpi,*vci);
-		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		read_unlock(&vcc_sklist_lock);
 		return err;
 	}
 	/* last scan may have left values out of bounds for current device */
@@ -90,7 +94,7 @@
 		if (!check_ci(vcc,p,c)) {
 			*vpi = p;
 			*vci = c;
-			spin_unlock_irqrestore(&vcc->dev->lock, flags);
+			read_unlock(&vcc_sklist_lock);
 			return 0;
 		}
 		if (*vci == ATM_VCI_ANY) {
@@ -105,7 +109,7 @@
 		}
 	}
 	while (old_p != p || old_c != c);
-	spin_unlock_irqrestore(&vcc->dev->lock, flags);
+	read_unlock(&vcc_sklist_lock);
 	return -EADDRINUSE;
 }
 
diff -Nru a/net/atm/clip.c b/net/atm/clip.c
--- a/net/atm/clip.c	Tue Jun 17 08:26:40 2003
+++ b/net/atm/clip.c	Tue Jun 17 08:26:40 2003
@@ -737,7 +737,8 @@
 	set_bit(ATM_VF_META,&vcc->flags);
 	set_bit(ATM_VF_READY,&vcc->flags);
 	    /* allow replies and avoid getting closed if signaling dies */
-	bind_vcc(vcc,&atmarpd_dev);
+	vcc->dev = &atmarpd_dev;
+	vcc_insert_socket(vcc->sk);
 	vcc->push = NULL;
 	vcc->pop = NULL; /* crash */
 	vcc->push_oam = NULL; /* crash */
diff -Nru a/net/atm/common.c b/net/atm/common.c
--- a/net/atm/common.c	Tue Jun 17 08:26:40 2003
+++ b/net/atm/common.c	Tue Jun 17 08:26:40 2003
@@ -157,6 +157,38 @@
 #endif
 
 
+struct sock *vcc_sklist;
+rwlock_t vcc_sklist_lock = RW_LOCK_UNLOCKED;
+
+void __vcc_insert_socket(struct sock *sk)
+{
+	sk->sk_next = vcc_sklist;
+	if (sk->sk_next)
+		vcc_sklist->sk_pprev = &sk->sk_next;
+	vcc_sklist = sk;
+	sk->sk_pprev = &vcc_sklist;
+}
+
+void vcc_insert_socket(struct sock *sk)
+{
+	write_lock_irq(&vcc_sklist_lock);
+	__vcc_insert_socket(sk);
+	write_unlock_irq(&vcc_sklist_lock);
+}
+
+void vcc_remove_socket(struct sock *sk)
+{
+	write_lock_irq(&vcc_sklist_lock);
+	if (sk->sk_pprev) {
+		if (sk->sk_next)
+			sk->sk_next->sk_pprev = sk->sk_pprev;
+		*sk->sk_pprev = sk->sk_next;
+		sk->sk_pprev = NULL;
+	}
+	write_unlock_irq(&vcc_sklist_lock);
+}
+
+
 static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
 {
 	struct sk_buff *skb;
@@ -175,16 +207,45 @@
 }
 
 
-int atm_create(struct socket *sock,int protocol,int family)
+EXPORT_SYMBOL(vcc_sklist);
+EXPORT_SYMBOL(vcc_sklist_lock);
+EXPORT_SYMBOL(vcc_insert_socket);
+EXPORT_SYMBOL(vcc_remove_socket);
+
+static void vcc_sock_destruct(struct sock *sk)
+{
+	struct atm_vcc *vcc = atm_sk(sk);
+
+	if (atomic_read(&vcc->sk->sk_rmem_alloc))
+		printk(KERN_DEBUG "vcc_sock_destruct: rmem leakage (%d bytes) detected.\n", atomic_read(&sk->sk_rmem_alloc));
+
+	if (atomic_read(&vcc->sk->sk_wmem_alloc))
+		printk(KERN_DEBUG "vcc_sock_destruct: wmem leakage (%d bytes) detected.\n", atomic_read(&sk->sk_wmem_alloc));
+
+	kfree(sk->sk_protinfo);
+}
+ 
+int vcc_create(struct socket *sock, int protocol, int family)
 {
 	struct sock *sk;
 	struct atm_vcc *vcc;
 
 	sock->sk = NULL;
-	if (sock->type == SOCK_STREAM) return -EINVAL;
-	if (!(sk = alloc_atm_vcc_sk(family))) return -ENOMEM;
-	vcc = atm_sk(sk);
-	memset(&vcc->flags,0,sizeof(vcc->flags));
+	if (sock->type == SOCK_STREAM)
+		return -EINVAL;
+	sk = sk_alloc(family, GFP_KERNEL, 1, NULL);
+	if (!sk)
+		return -ENOMEM;
+	sock_init_data(NULL, sk);
+
+	vcc = atm_sk(sk) = kmalloc(sizeof(*vcc), GFP_KERNEL);
+	if (!vcc) {
+		sk_free(sk);
+		return -ENOMEM;
+	}
+
+	memset(vcc, 0, sizeof(*vcc));
+	vcc->sk = sk;
 	vcc->dev = NULL;
 	vcc->callback = NULL;
 	memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc));
@@ -199,42 +260,49 @@
 	vcc->atm_options = vcc->aal_options = 0;
 	init_waitqueue_head(&vcc->sleep);
 	sk->sk_sleep = &vcc->sleep;
+	sk->sk_destruct = vcc_sock_destruct;
 	sock->sk = sk;
 	return 0;
 }
 
 
-void atm_release_vcc_sk(struct sock *sk,int free_sk)
+static void vcc_destroy_socket(struct sock *sk)
 {
 	struct atm_vcc *vcc = atm_sk(sk);
 	struct sk_buff *skb;
 
-	clear_bit(ATM_VF_READY,&vcc->flags);
+	clear_bit(ATM_VF_READY, &vcc->flags);
 	if (vcc->dev) {
-		if (vcc->dev->ops->close) vcc->dev->ops->close(vcc);
-		if (vcc->push) vcc->push(vcc,NULL); /* atmarpd has no push */
+		if (vcc->dev->ops->close)
+			vcc->dev->ops->close(vcc);
+		if (vcc->push)
+			vcc->push(vcc, NULL); /* atmarpd has no push */
+
+		vcc_remove_socket(sk);	/* no more receive */
+
 		while ((skb = skb_dequeue(&vcc->sk->sk_receive_queue))) {
 			atm_return(vcc,skb->truesize);
 			kfree_skb(skb);
 		}
 
 		module_put(vcc->dev->ops->owner);
-		atm_dev_release(vcc->dev);
-		if (atomic_read(&vcc->sk->sk_rmem_alloc))
-			printk(KERN_WARNING "atm_release_vcc: strange ... "
-			    "rmem_alloc == %d after closing\n",
-			    atomic_read(&vcc->sk->sk_rmem_alloc));
-		bind_vcc(vcc,NULL);
+		atm_dev_put(vcc->dev);
 	}
-
-	if (free_sk) free_atm_vcc_sk(sk);
 }
 
 
-int atm_release(struct socket *sock)
+int vcc_release(struct socket *sock)
 {
-	if (sock->sk)
-		atm_release_vcc_sk(sock->sk,1);
+	struct sock *sk = sock->sk;
+
+	if (sk) {
+		sock_orphan(sk);
+		lock_sock(sk);
+		vcc_destroy_socket(sock->sk);
+		release_sock(sk);
+		sock_put(sk);
+	}
+
 	return 0;
 }
 
@@ -289,7 +357,8 @@
 	if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE))
 		return -EPERM;
 	error = 0;
-	bind_vcc(vcc,dev);
+	vcc->dev = dev;
+	vcc_insert_socket(vcc->sk);
 	switch (vcc->qos.aal) {
 		case ATM_AAL0:
 			error = atm_init_aal0(vcc);
@@ -313,7 +382,7 @@
 	if (!error) error = adjust_tp(&vcc->qos.txtp,vcc->qos.aal);
 	if (!error) error = adjust_tp(&vcc->qos.rxtp,vcc->qos.aal);
 	if (error) {
-		bind_vcc(vcc,NULL);
+		vcc_remove_socket(vcc->sk);
 		return error;
 	}
 	DPRINTK("VCC %d.%d, AAL %d\n",vpi,vci,vcc->qos.aal);
@@ -327,7 +396,7 @@
 		error = dev->ops->open(vcc,vpi,vci);
 		if (error) {
 			module_put(dev->ops->owner);
-			bind_vcc(vcc,NULL);
+			vcc_remove_socket(vcc->sk);
 			return error;
 		}
 	}
@@ -371,7 +440,7 @@
 		dev = atm_dev_lookup(itf);
 		error = __vcc_connect(vcc, dev, vpi, vci);
 		if (error) {
-			atm_dev_release(dev);
+			atm_dev_put(dev);
 			return error;
 		}
 	} else {
@@ -385,7 +454,7 @@
 			spin_unlock(&atm_dev_lock);
 			if (!__vcc_connect(vcc, dev, vpi, vci))
 				break;
-			atm_dev_release(dev);
+			atm_dev_put(dev);
 			dev = NULL;
 			spin_lock(&atm_dev_lock);
 		}
diff -Nru a/net/atm/common.h b/net/atm/common.h
--- a/net/atm/common.h	Tue Jun 17 08:26:40 2003
+++ b/net/atm/common.h	Tue Jun 17 08:26:40 2003
@@ -10,8 +10,8 @@
 #include <linux/poll.h> /* for poll_table */
 
 
-int atm_create(struct socket *sock,int protocol,int family);
-int atm_release(struct socket *sock);
+int vcc_create(struct socket *sock, int protocol, int family);
+int vcc_release(struct socket *sock);
 int vcc_connect(struct socket *sock, int itf, short vpi, int vci);
 int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
 		int size, int flags);
@@ -24,7 +24,6 @@
 int vcc_getsockopt(struct socket *sock, int level, int optname, char *optval,
 		   int *optlen);
 
-void atm_release_vcc_sk(struct sock *sk,int free_sk);
 void atm_shutdown_dev(struct atm_dev *dev);
 
 int atmpvc_init(void);
diff -Nru a/net/atm/lec.c b/net/atm/lec.c
--- a/net/atm/lec.c	Tue Jun 17 08:26:40 2003
+++ b/net/atm/lec.c	Tue Jun 17 08:26:40 2003
@@ -48,7 +48,7 @@
 
 #include "lec.h"
 #include "lec_arpc.h"
-#include "resources.h"  /* for bind_vcc() */
+#include "resources.h"
 
 #if 0
 #define DPRINTK printk
@@ -810,7 +810,8 @@
         lec_arp_init(priv);
 	priv->itfnum = i;  /* LANE2 addition */
         priv->lecd = vcc;
-        bind_vcc(vcc, &lecatm_dev);
+        vcc->dev = &lecatm_dev;
+        vcc_insert_socket(vcc->sk);
         
         vcc->proto_data = dev_lec[i];
 	set_bit(ATM_VF_META,&vcc->flags);
diff -Nru a/net/atm/mpc.c b/net/atm/mpc.c
--- a/net/atm/mpc.c	Tue Jun 17 08:26:40 2003
+++ b/net/atm/mpc.c	Tue Jun 17 08:26:40 2003
@@ -28,7 +28,7 @@
 
 #include "lec.h"
 #include "mpc.h"
-#include "resources.h"  /* for bind_vcc() */
+#include "resources.h"
 
 /*
  * mpc.c: Implementation of MPOA client kernel part 
@@ -789,7 +789,8 @@
 	}
 
 	mpc->mpoad_vcc = vcc;
-	bind_vcc(vcc, &mpc_dev);
+	vcc->dev = &mpc_dev;
+	vcc_insert_socket(vcc->sk);
 	set_bit(ATM_VF_META,&vcc->flags);
 	set_bit(ATM_VF_READY,&vcc->flags);
 
diff -Nru a/net/atm/proc.c b/net/atm/proc.c
--- a/net/atm/proc.c	Tue Jun 17 08:26:40 2003
+++ b/net/atm/proc.c	Tue Jun 17 08:26:40 2003
@@ -334,9 +334,7 @@
 
 static int atm_pvc_info(loff_t pos,char *buf)
 {
-	unsigned long flags;
-	struct atm_dev *dev;
-	struct list_head *p;
+	struct sock *s;
 	struct atm_vcc *vcc;
 	int left, clip_info = 0;
 
@@ -349,25 +347,20 @@
 	if (try_atm_clip_ops())
 		clip_info = 1;
 #endif
-	spin_lock(&atm_dev_lock);
-	list_for_each(p, &atm_devs) {
-		dev = list_entry(p, struct atm_dev, dev_list);
-		spin_lock_irqsave(&dev->lock, flags);
-		for (vcc = dev->vccs; vcc; vcc = vcc->next)
-			if (vcc->sk->sk_family == PF_ATMPVC &&
-			    vcc->dev && !left--) {
-				pvc_info(vcc,buf,clip_info);
-				spin_unlock_irqrestore(&dev->lock, flags);
-				spin_unlock(&atm_dev_lock);
+	read_lock(&vcc_sklist_lock);
+	for(s = vcc_sklist; s; s = s->sk_next) {
+		vcc = atm_sk(s);
+		if (vcc->sk->sk_family == PF_ATMPVC && vcc->dev && !left--) {
+			pvc_info(vcc,buf,clip_info);
+			read_unlock(&vcc_sklist_lock);
 #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
-				if (clip_info)
-					module_put(atm_clip_ops->owner);
+			if (clip_info)
+				module_put(atm_clip_ops->owner);
 #endif
-				return strlen(buf);
-			}
-		spin_unlock_irqrestore(&dev->lock, flags);
+			return strlen(buf);
+		}
 	}
-	spin_unlock(&atm_dev_lock);
+	read_unlock(&vcc_sklist_lock);
 #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
 	if (clip_info)
 		module_put(atm_clip_ops->owner);
@@ -378,10 +371,8 @@
 
 static int atm_vc_info(loff_t pos,char *buf)
 {
-	unsigned long flags;
-	struct atm_dev *dev;
-	struct list_head *p;
 	struct atm_vcc *vcc;
+	struct sock *s;
 	int left;
 
 	if (!pos)
@@ -389,20 +380,16 @@
 		    "Address"," Itf VPI VCI   Fam Flags Reply Send buffer"
 		    "     Recv buffer\n");
 	left = pos-1;
-	spin_lock(&atm_dev_lock);
-	list_for_each(p, &atm_devs) {
-		dev = list_entry(p, struct atm_dev, dev_list);
-		spin_lock_irqsave(&dev->lock, flags);
-		for (vcc = dev->vccs; vcc; vcc = vcc->next)
-			if (!left--) {
-				vc_info(vcc,buf);
-				spin_unlock_irqrestore(&dev->lock, flags);
-				spin_unlock(&atm_dev_lock);
-				return strlen(buf);
-			}
-		spin_unlock_irqrestore(&dev->lock, flags);
+	read_lock(&vcc_sklist_lock);
+	for(s = vcc_sklist; s; s = s->sk_next) {
+		vcc = atm_sk(s);
+		if (!left--) {
+			vc_info(vcc,buf);
+			read_unlock(&vcc_sklist_lock);
+			return strlen(buf);
+		}
 	}
-	spin_unlock(&atm_dev_lock);
+	read_unlock(&vcc_sklist_lock);
 
 	return 0;
 }
@@ -410,29 +397,23 @@
 
 static int atm_svc_info(loff_t pos,char *buf)
 {
-	unsigned long flags;
-	struct atm_dev *dev;
-	struct list_head *p;
+	struct sock *s;
 	struct atm_vcc *vcc;
 	int left;
 
 	if (!pos)
 		return sprintf(buf,"Itf VPI VCI           State      Remote\n");
 	left = pos-1;
-	spin_lock(&atm_dev_lock);
-	list_for_each(p, &atm_devs) {
-		dev = list_entry(p, struct atm_dev, dev_list);
-		spin_lock_irqsave(&dev->lock, flags);
-		for (vcc = dev->vccs; vcc; vcc = vcc->next)
-			if (vcc->sk->sk_family == PF_ATMSVC && !left--) {
-				svc_info(vcc,buf);
-				spin_unlock_irqrestore(&dev->lock, flags);
-				spin_unlock(&atm_dev_lock);
-				return strlen(buf);
-			}
-		spin_unlock_irqrestore(&dev->lock, flags);
+	read_lock(&vcc_sklist_lock);
+	for(s = vcc_sklist; s; s = s->sk_next) {
+		vcc = atm_sk(s);
+		if (vcc->sk->sk_family == PF_ATMSVC && !left--) {
+			svc_info(vcc,buf);
+			read_unlock(&vcc_sklist_lock);
+			return strlen(buf);
+		}
 	}
-	spin_unlock(&atm_dev_lock);
+	read_unlock(&vcc_sklist_lock);
 
 	return 0;
 }
diff -Nru a/net/atm/pvc.c b/net/atm/pvc.c
--- a/net/atm/pvc.c	Tue Jun 17 08:26:40 2003
+++ b/net/atm/pvc.c	Tue Jun 17 08:26:40 2003
@@ -17,10 +17,6 @@
 #include "resources.h"		/* devs and vccs */
 #include "common.h"		/* common for PVCs and SVCs */
 
-#ifndef NULL
-#define NULL 0
-#endif
-
 
 static int pvc_shutdown(struct socket *sock,int how)
 {
@@ -109,7 +105,7 @@
 static struct proto_ops pvc_proto_ops = {
 	.family =	PF_ATMPVC,
 
-	.release =	atm_release,
+	.release =	vcc_release,
 	.bind =		pvc_bind,
 	.connect =	pvc_connect,
 	.socketpair =	sock_no_socketpair,
@@ -131,7 +127,7 @@
 static int pvc_create(struct socket *sock,int protocol)
 {
 	sock->ops = &pvc_proto_ops;
-	return atm_create(sock,protocol,PF_ATMPVC);
+	return vcc_create(sock, protocol, PF_ATMPVC);
 }
 
 
diff -Nru a/net/atm/resources.c b/net/atm/resources.c
--- a/net/atm/resources.c	Tue Jun 17 08:26:40 2003
+++ b/net/atm/resources.c	Tue Jun 17 08:26:40 2003
@@ -23,11 +23,6 @@
 #include "addr.h"
 
 
-#ifndef NULL
-#define NULL 0
-#endif
-
-
 LIST_HEAD(atm_devs);
 spinlock_t atm_dev_lock = SPIN_LOCK_UNLOCKED;
 
@@ -91,7 +86,7 @@
 	spin_lock(&atm_dev_lock);
 	if (number != -1) {
 		if ((inuse = __atm_dev_lookup(number))) {
-			atm_dev_release(inuse);
+			atm_dev_put(inuse);
 			spin_unlock(&atm_dev_lock);
 			__free_atm_dev(dev);
 			return NULL;
@@ -100,7 +95,7 @@
 	} else {
 		dev->number = 0;
 		while ((inuse = __atm_dev_lookup(dev->number))) {
-			atm_dev_release(inuse);
+			atm_dev_put(inuse);
 			dev->number++;
 		}
 	}
@@ -402,78 +397,12 @@
 	else
 		error = 0;
 done:
-	atm_dev_release(dev);
+	atm_dev_put(dev);
 	return error;
 }
 
 
-struct sock *alloc_atm_vcc_sk(int family)
-{
-	struct sock *sk;
-	struct atm_vcc *vcc;
-
-	sk = sk_alloc(family, GFP_KERNEL, 1, NULL);
-	if (!sk)
-		return NULL;
-	vcc = atm_sk(sk) = kmalloc(sizeof(*vcc), GFP_KERNEL);
-	if (!vcc) {
-		sk_free(sk);
-		return NULL;
-	}
-	sock_init_data(NULL, sk);
-	memset(vcc, 0, sizeof(*vcc));
-	vcc->sk = sk;
-
-	return sk;
-}
-
-
-static void unlink_vcc(struct atm_vcc *vcc)
-{
-	unsigned long flags;
-	if (vcc->dev) {
-		spin_lock_irqsave(&vcc->dev->lock, flags);
-		if (vcc->prev)
-			vcc->prev->next = vcc->next;
-		else
-			vcc->dev->vccs = vcc->next;
-
-		if (vcc->next)
-			vcc->next->prev = vcc->prev;
-		else
-			vcc->dev->last = vcc->prev;
-		spin_unlock_irqrestore(&vcc->dev->lock, flags);
-	}
-}
-
-
-void free_atm_vcc_sk(struct sock *sk)
-{
-	unlink_vcc(atm_sk(sk));
-	sk_free(sk);
-}
-
-void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev)
-{
-	unsigned long flags;
-
-	unlink_vcc(vcc);
-	vcc->dev = dev;
-	if (dev) {
-		spin_lock_irqsave(&dev->lock, flags);
-		vcc->next = NULL;
-		vcc->prev = dev->last;
-		if (dev->vccs)
-			dev->last->next = vcc;
-		else
-			dev->vccs = vcc;
-		dev->last = vcc;
-		spin_unlock_irqrestore(&dev->lock, flags);
-	}
-}
-
 EXPORT_SYMBOL(atm_dev_register);
 EXPORT_SYMBOL(atm_dev_deregister);
 EXPORT_SYMBOL(atm_dev_lookup);
 EXPORT_SYMBOL(shutdown_atm_dev);
-EXPORT_SYMBOL(bind_vcc);
diff -Nru a/net/atm/resources.h b/net/atm/resources.h
--- a/net/atm/resources.h	Tue Jun 17 08:26:40 2003
+++ b/net/atm/resources.h	Tue Jun 17 08:26:40 2003
@@ -14,8 +14,6 @@
 extern spinlock_t atm_dev_lock;
 
 
-struct sock *alloc_atm_vcc_sk(int family);
-void free_atm_vcc_sk(struct sock *sk);
 int atm_dev_ioctl(unsigned int cmd, unsigned long arg);
 
 
diff -Nru a/net/atm/signaling.c b/net/atm/signaling.c
--- a/net/atm/signaling.c	Tue Jun 17 08:26:40 2003
+++ b/net/atm/signaling.c	Tue Jun 17 08:26:40 2003
@@ -200,26 +200,21 @@
 }
 
 
-static void purge_vccs(struct atm_vcc *vcc)
+static void purge_vcc(struct atm_vcc *vcc)
 {
-	while (vcc) {
-		if (vcc->sk->sk_family == PF_ATMSVC &&
-		    !test_bit(ATM_VF_META,&vcc->flags)) {
-			set_bit(ATM_VF_RELEASED,&vcc->flags);
-			vcc->reply = -EUNATCH;
-			vcc->sk->sk_err = EUNATCH;
-			wake_up(&vcc->sleep);
-		}
-		vcc = vcc->next;
+	if (vcc->sk->sk_family == PF_ATMSVC &&
+	    !test_bit(ATM_VF_META,&vcc->flags)) {
+		set_bit(ATM_VF_RELEASED,&vcc->flags);
+		vcc->reply = -EUNATCH;
+		vcc->sk->sk_err = EUNATCH;
+		wake_up(&vcc->sleep);
 	}
 }
 
 
 static void sigd_close(struct atm_vcc *vcc)
 {
-	unsigned long flags;
-	struct atm_dev *dev;
-	struct list_head *p;
+	struct sock *s;
 
 	DPRINTK("sigd_close\n");
 	sigd = NULL;
@@ -227,14 +222,14 @@
 		printk(KERN_ERR "sigd_close: closing with requests pending\n");
 	skb_queue_purge(&vcc->sk->sk_receive_queue);
 
-	spin_lock(&atm_dev_lock);
-	list_for_each(p, &atm_devs) {
-		dev = list_entry(p, struct atm_dev, dev_list);
-		spin_lock_irqsave(&dev->lock, flags);
-		purge_vccs(dev->vccs);
-		spin_unlock_irqrestore(&dev->lock, flags);
+	read_lock(&vcc_sklist_lock);
+	for(s = vcc_sklist; s; s = s->sk_next) {
+		struct atm_vcc *vcc = atm_sk(s);
+
+		if (vcc->dev)
+			purge_vcc(vcc);
 	}
-	spin_unlock(&atm_dev_lock);
+	read_unlock(&vcc_sklist_lock);
 }
 
 
@@ -257,7 +252,8 @@
 	if (sigd) return -EADDRINUSE;
 	DPRINTK("sigd_attach\n");
 	sigd = vcc;
-	bind_vcc(vcc,&sigd_dev);
+	vcc->dev = &sigd_dev;
+	vcc_insert_socket(vcc->sk);
 	set_bit(ATM_VF_META,&vcc->flags);
 	set_bit(ATM_VF_READY,&vcc->flags);
 	wake_up(&sigd_sleep);
diff -Nru a/net/atm/svc.c b/net/atm/svc.c
--- a/net/atm/svc.c	Tue Jun 17 08:26:40 2003
+++ b/net/atm/svc.c	Tue Jun 17 08:26:40 2003
@@ -88,18 +88,21 @@
 
 static int svc_release(struct socket *sock)
 {
+	struct sock *sk = sock->sk;
 	struct atm_vcc *vcc;
 
-	if (!sock->sk) return 0;
-	vcc = ATM_SD(sock);
-	DPRINTK("svc_release %p\n",vcc);
-	clear_bit(ATM_VF_READY,&vcc->flags);
-	atm_release_vcc_sk(sock->sk,0);
-	svc_disconnect(vcc);
-	    /* VCC pointer is used as a reference, so we must not free it
-	       (thereby subjecting it to re-use) before all pending connections
-	        are closed */
-	free_atm_vcc_sk(sock->sk);
+	if (sk)  {
+		vcc = ATM_SD(sock);
+		DPRINTK("svc_release %p\n", vcc);
+		clear_bit(ATM_VF_READY, &vcc->flags);
+		/* VCC pointer is used as a reference, so we must not free it
+		   (thereby subjecting it to re-use) before all pending connections
+	           are closed */
+		sock_hold(sk);
+		vcc_release(sock);
+		svc_disconnect(vcc);
+		sock_put(sk);
+	}
 	return 0;
 }
 
@@ -542,7 +545,7 @@
 	int error;
 
 	sock->ops = &svc_proto_ops;
-	error = atm_create(sock,protocol,AF_ATMSVC);
+	error = vcc_create(sock, protocol, AF_ATMSVC);
 	if (error) return error;
 	ATM_SD(sock)->callback = svc_callback;
 	ATM_SD(sock)->local.sas_family = AF_ATMSVC;

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

* Re: [PATCH][ATM][3/3] assorted changes for atm
  2003-06-17 12:40 [PATCH][ATM][3/3] assorted changes for atm chas williams
@ 2003-06-17 17:31 ` David S. Miller
  2003-06-18 15:24   ` chas williams
  2003-06-20 20:53   ` chas williams
  0 siblings, 2 replies; 5+ messages in thread
From: David S. Miller @ 2003-06-17 17:31 UTC (permalink / raw)
  To: chas; +Cc: netdev

   From: chas williams <chas@cmf.nrl.navy.mil>
   Date: Tue, 17 Jun 2003 08:40:22 -0400

   
   [atm]: keep vcc's on global list instead of per device
   
I've applied all 3 of your patches.

Thanks.

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

* Re: [PATCH][ATM][3/3] assorted changes for atm
  2003-06-17 17:31 ` David S. Miller
@ 2003-06-18 15:24   ` chas williams
  2003-06-20 20:53   ` chas williams
  1 sibling, 0 replies; 5+ messages in thread
From: chas williams @ 2003-06-18 15:24 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev

i has been brought to my attention that my vcc sklist patch didnt take
advantage of the new hlist changes.  here is an updated version relative
to 2.5.72.

[atm]: move vcc's to global sk-based linked list

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.1332  -> 1.1333 
#	    drivers/atm/he.c	1.14    -> 1.15   
#	  net/atm/atm_misc.c	1.6     -> 1.7    
#	   drivers/atm/eni.c	1.16    -> 1.17   
#	      net/atm/proc.c	1.19    -> 1.20   
#	       net/atm/pvc.c	1.15    -> 1.16   
#	drivers/atm/idt77252.c	1.16    -> 1.17   
#	       net/atm/lec.c	1.28    -> 1.29   
#	drivers/atm/atmtcp.c	1.9     -> 1.10   
#	       net/atm/svc.c	1.17    -> 1.18   
#	    net/atm/common.h	1.11    -> 1.12   
#	 net/atm/signaling.c	1.13    -> 1.14   
#	 net/atm/resources.h	1.6     -> 1.7    
#	       net/atm/mpc.c	1.19    -> 1.20   
#	include/linux/atmdev.h	1.17    -> 1.18   
#	 net/atm/resources.c	1.12    -> 1.13   
#	      net/atm/clip.c	1.16    -> 1.17   
#	drivers/atm/fore200e.c	1.17    -> 1.18   
#	    net/atm/common.c	1.34    -> 1.35   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/06/18	chas@relax.cmf.nrl.navy.mil	1.1333
# move vcc's to global sk-based linked list
# --------------------------------------------
#
diff -Nru a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c
--- a/drivers/atm/atmtcp.c	Wed Jun 18 11:19:12 2003
+++ b/drivers/atm/atmtcp.c	Wed Jun 18 11:19:12 2003
@@ -153,9 +153,10 @@
 
 static int atmtcp_v_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
 {
-	unsigned long flags;
 	struct atm_cirange ci;
 	struct atm_vcc *vcc;
+	struct hlist_node *node;
+	struct sock *s;
 
 	if (cmd != ATM_SETCIRANGE) return -ENOIOCTLCMD;
 	if (copy_from_user(&ci,(void *) arg,sizeof(ci))) return -EFAULT;
@@ -163,14 +164,18 @@
 	if (ci.vci_bits == ATM_CI_MAX) ci.vci_bits = MAX_VCI_BITS;
 	if (ci.vpi_bits > MAX_VPI_BITS || ci.vpi_bits < 0 ||
 	    ci.vci_bits > MAX_VCI_BITS || ci.vci_bits < 0) return -EINVAL;
-	spin_lock_irqsave(&dev->lock, flags);
-	for (vcc = dev->vccs; vcc; vcc = vcc->next)
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+		vcc = atm_sk(s);
+		if (vcc->dev != dev)
+			continue;
 		if ((vcc->vpi >> ci.vpi_bits) ||
 		    (vcc->vci >> ci.vci_bits)) {
-			spin_unlock_irqrestore(&dev->lock, flags);
+			read_unlock(&vcc_sklist_lock);
 			return -EBUSY;
 		}
-	spin_unlock_irqrestore(&dev->lock, flags);
+	}
+	read_unlock(&vcc_sklist_lock);
 	dev->ci_range = ci;
 	return 0;
 }
@@ -233,9 +238,10 @@
 
 static void atmtcp_c_close(struct atm_vcc *vcc)
 {
-	unsigned long flags;
 	struct atm_dev *atmtcp_dev;
 	struct atmtcp_dev_data *dev_data;
+	struct sock *s;
+	struct hlist_node *node;
 	struct atm_vcc *walk;
 
 	atmtcp_dev = (struct atm_dev *) vcc->dev_data;
@@ -246,19 +252,24 @@
 	kfree(dev_data);
 	shutdown_atm_dev(atmtcp_dev);
 	vcc->dev_data = NULL;
-	spin_lock_irqsave(&atmtcp_dev->lock, flags);
-	for (walk = atmtcp_dev->vccs; walk; walk = walk->next)
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+		walk = atm_sk(s);
+		if (walk->dev != atmtcp_dev)
+			continue;
 		wake_up(&walk->sleep);
-	spin_unlock_irqrestore(&atmtcp_dev->lock, flags);
+	}
+	read_unlock(&vcc_sklist_lock);
 }
 
 
 static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb)
 {
-	unsigned long flags;
 	struct atm_dev *dev;
 	struct atmtcp_hdr *hdr;
-	struct atm_vcc *out_vcc;
+	struct sock *s;
+	struct hlist_node *node;
+	struct atm_vcc *out_vcc = NULL;
 	struct sk_buff *new_skb;
 	int result = 0;
 
@@ -270,13 +281,17 @@
 		    (struct atmtcp_control *) skb->data);
 		goto done;
 	}
-	spin_lock_irqsave(&dev->lock, flags);
-	for (out_vcc = dev->vccs; out_vcc; out_vcc = out_vcc->next)
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+		out_vcc = atm_sk(s);
+		if (out_vcc->dev != dev)
+			continue;
 		if (out_vcc->vpi == ntohs(hdr->vpi) &&
 		    out_vcc->vci == ntohs(hdr->vci) &&
 		    out_vcc->qos.rxtp.traffic_class != ATM_NONE)
 			break;
-	spin_unlock_irqrestore(&dev->lock, flags);
+	}
+	read_unlock(&vcc_sklist_lock);
 	if (!out_vcc) {
 		atomic_inc(&vcc->stats->tx_err);
 		goto done;
@@ -366,7 +381,7 @@
 	if (itf != -1) dev = atm_dev_lookup(itf);
 	if (dev) {
 		if (dev->ops != &atmtcp_v_dev_ops) {
-			atm_dev_release(dev);
+			atm_dev_put(dev);
 			return -EMEDIUMTYPE;
 		}
 		if (PRIV(dev)->vcc) return -EBUSY;
@@ -378,7 +393,8 @@
 		if (error) return error;
 	}
 	PRIV(dev)->vcc = vcc;
-	bind_vcc(vcc,&atmtcp_control_dev);
+	vcc->dev = &atmtcp_control_dev;
+	vcc_insert_socket(vcc->sk);
 	set_bit(ATM_VF_META,&vcc->flags);
 	set_bit(ATM_VF_READY,&vcc->flags);
 	vcc->dev_data = dev;
@@ -402,7 +418,7 @@
 	dev = atm_dev_lookup(itf);
 	if (!dev) return -ENODEV;
 	if (dev->ops != &atmtcp_v_dev_ops) {
-		atm_dev_release(dev);
+		atm_dev_put(dev);
 		return -EMEDIUMTYPE;
 	}
 	dev_data = PRIV(dev);
@@ -410,7 +426,7 @@
 	dev_data->persist = 0;
 	if (PRIV(dev)->vcc) return 0;
 	kfree(dev_data);
-	atm_dev_release(dev);
+	atm_dev_put(dev);
 	shutdown_atm_dev(dev);
 	return 0;
 }
diff -Nru a/drivers/atm/eni.c b/drivers/atm/eni.c
--- a/drivers/atm/eni.c	Wed Jun 18 11:19:12 2003
+++ b/drivers/atm/eni.c	Wed Jun 18 11:19:12 2003
@@ -1887,10 +1887,11 @@
 
 static int get_ci(struct atm_vcc *vcc,short *vpi,int *vci)
 {
-	unsigned long flags;
+	struct sock *s;
+	struct hlist_node *node;
 	struct atm_vcc *walk;
 
-	spin_lock_irqsave(&vcc->dev->lock, flags);
+	read_lock(&vcc_sklist_lock);
 	if (*vpi == ATM_VPI_ANY) *vpi = 0;
 	if (*vci == ATM_VCI_ANY) {
 		for (*vci = ATM_NOT_RSV_VCI; *vci < NR_VCI; (*vci)++) {
@@ -1898,40 +1899,48 @@
 			    ENI_DEV(vcc->dev)->rx_map[*vci])
 				continue;
 			if (vcc->qos.txtp.traffic_class != ATM_NONE) {
-				for (walk = vcc->dev->vccs; walk;
-				    walk = walk->next)
+				s = NULL;
+				sk_for_each(s, node, &vcc_sklist) {
+					walk = atm_sk(s);
+					if (walk->dev != vcc->dev)
+						continue;
 					if (test_bit(ATM_VF_ADDR,&walk->flags)
 					    && walk->vci == *vci &&
 					    walk->qos.txtp.traffic_class !=
 					    ATM_NONE)
 						break;
-				if (walk) continue;
+				}
+				if (s) continue;
 			}
 			break;
 		}
-		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		read_unlock(&vcc_sklist_lock);
 		return *vci == NR_VCI ? -EADDRINUSE : 0;
 	}
 	if (*vci == ATM_VCI_UNSPEC) {
-		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		read_unlock(&vcc_sklist_lock);
 		return 0;
 	}
 	if (vcc->qos.rxtp.traffic_class != ATM_NONE &&
 	    ENI_DEV(vcc->dev)->rx_map[*vci]) {
-		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		read_unlock(&vcc_sklist_lock);
 		return -EADDRINUSE;
 	}
 	if (vcc->qos.txtp.traffic_class == ATM_NONE) {
-		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		read_unlock(&vcc_sklist_lock);
 		return 0;
 	}
-	for (walk = vcc->dev->vccs; walk; walk = walk->next)
+	sk_for_each(s, node, &vcc_sklist) {
+		walk = atm_sk(s);
+		if (walk->dev != vcc->dev)
+			continue;
 		if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vci == *vci &&
 		    walk->qos.txtp.traffic_class != ATM_NONE) {
-			spin_unlock_irqrestore(&vcc->dev->lock, flags);
+			read_unlock(&vcc_sklist_lock);
 			return -EADDRINUSE;
 		}
-	spin_unlock_irqrestore(&vcc->dev->lock, flags);
+	}
+	read_unlock(&vcc_sklist_lock);
 	return 0;
 }
 
@@ -2139,7 +2148,8 @@
 
 static int eni_proc_read(struct atm_dev *dev,loff_t *pos,char *page)
 {
-	unsigned long flags;
+	struct hlist_node *node;
+	struct sock *s;
 	static const char *signal[] = { "LOST","unknown","okay" };
 	struct eni_dev *eni_dev = ENI_DEV(dev);
 	struct atm_vcc *vcc;
@@ -2212,11 +2222,15 @@
 		return sprintf(page,"%10sbacklog %u packets\n","",
 		    skb_queue_len(&tx->backlog));
 	}
-	spin_lock_irqsave(&dev->lock, flags);
-	for (vcc = dev->vccs; vcc; vcc = vcc->next) {
-		struct eni_vcc *eni_vcc = ENI_VCC(vcc);
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+		struct eni_vcc *eni_vcc;
 		int length;
 
+		vcc = atm_sk(s);
+		if (vcc->dev != dev)
+			continue;
+		eni_vcc = ENI_VCC(vcc);
 		if (--left) continue;
 		length = sprintf(page,"vcc %4d: ",vcc->vci);
 		if (eni_vcc->rx) {
@@ -2231,10 +2245,10 @@
 			length += sprintf(page+length,"tx[%d], txing %d bytes",
 			    eni_vcc->tx->index,eni_vcc->txing);
 		page[length] = '\n';
-		spin_unlock_irqrestore(&dev->lock, flags);
+		read_unlock(&vcc_sklist_lock);
 		return length+1;
 	}
-	spin_unlock_irqrestore(&dev->lock, flags);
+	read_unlock(&vcc_sklist_lock);
 	for (i = 0; i < eni_dev->free_len; i++) {
 		struct eni_free *fe = eni_dev->free_list+i;
 		unsigned long offset;
diff -Nru a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
--- a/drivers/atm/fore200e.c	Wed Jun 18 11:19:12 2003
+++ b/drivers/atm/fore200e.c	Wed Jun 18 11:19:12 2003
@@ -1069,18 +1069,23 @@
 static struct atm_vcc* 
 fore200e_find_vcc(struct fore200e* fore200e, struct rpd* rpd)
 {
-    unsigned long flags;
+    struct sock *s;
     struct atm_vcc* vcc;
+    struct hlist_node *node;
 
-    spin_lock_irqsave(&fore200e->atm_dev->lock, flags);
-    for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) {
-
-	if (vcc->vpi == rpd->atm_header.vpi && vcc->vci == rpd->atm_header.vci)
-	    break;
+    read_lock(&vcc_sklist_lock);
+    sk_for_each(s, node, &vcc_sklist) {
+	vcc = atm_sk(s);
+	if (vcc->dev != fore200e->atm_dev)
+		continue;
+	if (vcc->vpi == rpd->atm_header.vpi && vcc->vci == rpd->atm_header.vci) {
+            read_unlock(&vcc_sklist_lock);
+	    return vcc;
+	}
     }
-    spin_unlock_irqrestore(&fore200e->atm_dev->lock, flags);
-    
-    return vcc;
+    read_unlock(&vcc_sklist_lock);
+
+    return NULL;
 }
 
 
@@ -1350,20 +1355,26 @@
 static int
 fore200e_walk_vccs(struct atm_vcc *vcc, short *vpi, int *vci)
 {
-    unsigned long flags;
     struct atm_vcc* walk;
+    struct sock *s;
+    struct hlist_node *node;
 
     /* find a free VPI */
 
-    spin_lock_irqsave(&vcc->dev->lock, flags);
+    read_lock(&vcc_sklist_lock);
 
     if (*vpi == ATM_VPI_ANY) {
 
-	for (*vpi = 0, walk = vcc->dev->vccs; walk; walk = walk->next) {
+	*vpi = 0;
+restart_vpi_search:
+	sk_for_each(s, node, &vcc_sklist) {
+	    walk = atm_sk(s);
+	    if (walk->dev != vcc->dev)
+		continue;
 
 	    if ((walk->vci == *vci) && (walk->vpi == *vpi)) {
 		(*vpi)++;
-		walk = vcc->dev->vccs;
+		goto restart_vpi_search;
 	    }
 	}
     }
@@ -1371,16 +1382,21 @@
     /* find a free VCI */
     if (*vci == ATM_VCI_ANY) {
 	
-	for (*vci = ATM_NOT_RSV_VCI, walk = vcc->dev->vccs; walk; walk = walk->next) {
+	*vci = ATM_NOT_RSV_VCI;
+restart_vci_search:
+	sk_for_each(s, node, &vcc_sklist) {
+	    walk = atm_sk(s);
+	    if (walk->dev != vcc->dev)
+		continue;
 
 	    if ((walk->vpi = *vpi) && (walk->vci == *vci)) {
 		*vci = walk->vci + 1;
-		walk = vcc->dev->vccs;
+		goto restart_vci_search;
 	    }
 	}
     }
 
-    spin_unlock_irqrestore(&vcc->dev->lock, flags);
+    read_unlock(&vcc_sklist_lock);
 
     return 0;
 }
@@ -2642,7 +2658,8 @@
 static int
 fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page)
 {
-    unsigned long flags;
+    struct sock *s;
+    struct hlist_node *node;
     struct fore200e* fore200e  = FORE200E_DEV(dev);
     int              len, left = *pos;
 
@@ -2889,8 +2906,12 @@
 	len = sprintf(page,"\n"    
 		      " VCCs:\n  address\tVPI.VCI:AAL\t(min/max tx PDU size) (min/max rx PDU size)\n");
 	
-	spin_lock_irqsave(&fore200e->atm_dev->lock, flags);
-	for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) {
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+	    vcc = atm_sk(s);
+
+	    if (vcc->dev != fore200e->atm_dev)
+		    continue;
 
 	    fore200e_vcc = FORE200E_VCC(vcc);
 	    
@@ -2904,7 +2925,7 @@
 			   fore200e_vcc->rx_max_pdu
 		);
 	}
-	spin_unlock_irqrestore(&fore200e->atm_dev->lock, flags);
+	read_unlock(&vcc_sklist_lock);
 
 	return len;
     }
diff -Nru a/drivers/atm/he.c b/drivers/atm/he.c
--- a/drivers/atm/he.c	Wed Jun 18 11:19:12 2003
+++ b/drivers/atm/he.c	Wed Jun 18 11:19:12 2003
@@ -79,7 +79,6 @@
 #include <linux/sonet.h>
 
 #define USE_TASKLET
-#define USE_HE_FIND_VCC
 #undef USE_SCATTERGATHER
 #undef USE_CHECKSUM_HW			/* still confused about this */
 #define USE_RBPS
@@ -328,25 +327,25 @@
 		he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 7)
 
 static __inline__ struct atm_vcc*
-he_find_vcc(struct he_dev *he_dev, unsigned cid)
+__find_vcc(struct he_dev *he_dev, unsigned cid)
 {
-	unsigned long flags;
 	struct atm_vcc *vcc;
+	struct hlist_node *node;
+	struct sock *s;
 	short vpi;
 	int vci;
 
 	vpi = cid >> he_dev->vcibits;
 	vci = cid & ((1 << he_dev->vcibits) - 1);
 
-	spin_lock_irqsave(&he_dev->atm_dev->lock, flags);
-	for (vcc = he_dev->atm_dev->vccs; vcc; vcc = vcc->next)
-		if (vcc->vci == vci && vcc->vpi == vpi
-			&& vcc->qos.rxtp.traffic_class != ATM_NONE) {
-				spin_unlock_irqrestore(&he_dev->atm_dev->lock, flags);
+	sk_for_each(s, node, &vcc_sklist) {
+		vcc = atm_sk(s);
+		if (vcc->dev == he_dev->atm_dev &&
+		    vcc->vci == vci && vcc->vpi == vpi &&
+		    vcc->qos.rxtp.traffic_class != ATM_NONE) {
 				return vcc;
-			}
-
-	spin_unlock_irqrestore(&he_dev->atm_dev->lock, flags);
+		}
+	}
 	return NULL;
 }
 
@@ -1566,17 +1565,6 @@
 	reg |= RX_ENABLE;
 	he_writel(he_dev, reg, RC_CONFIG);
 
-#ifndef USE_HE_FIND_VCC
-	he_dev->he_vcc_table = kmalloc(sizeof(struct he_vcc_table) * 
-			(1 << (he_dev->vcibits + he_dev->vpibits)), GFP_KERNEL);
-	if (he_dev->he_vcc_table == NULL) {
-		hprintk("failed to alloc he_vcc_table\n");
-		return -ENOMEM;
-	}
-	memset(he_dev->he_vcc_table, 0, sizeof(struct he_vcc_table) *
-				(1 << (he_dev->vcibits + he_dev->vpibits)));
-#endif
-
 	for (i = 0; i < HE_NUM_CS_STPER; ++i) {
 		he_dev->cs_stper[i].inuse = 0;
 		he_dev->cs_stper[i].pcr = -1;
@@ -1712,11 +1700,6 @@
 							he_dev->tpd_base, he_dev->tpd_base_phys);
 #endif
 
-#ifndef USE_HE_FIND_VCC
-	if (he_dev->he_vcc_table)
-		kfree(he_dev->he_vcc_table);
-#endif
-
 	if (he_dev->pci_dev) {
 		pci_read_config_word(he_dev->pci_dev, PCI_COMMAND, &command);
 		command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
@@ -1798,6 +1781,7 @@
 	int pdus_assembled = 0;
 	int updated = 0;
 
+	read_lock(&vcc_sklist_lock);
 	while (he_dev->rbrq_head != rbrq_tail) {
 		++updated;
 
@@ -1823,13 +1807,10 @@
 		buf_len = RBRQ_BUFLEN(he_dev->rbrq_head) * 4;
 		cid = RBRQ_CID(he_dev->rbrq_head);
 
-#ifdef USE_HE_FIND_VCC
 		if (cid != lastcid)
-			vcc = he_find_vcc(he_dev, cid);
+			vcc = __find_vcc(he_dev, cid);
 		lastcid = cid;
-#else
-		vcc = HE_LOOKUP_VCC(he_dev, cid);
-#endif
+
 		if (vcc == NULL) {
 			hprintk("vcc == NULL  (cid 0x%x)\n", cid);
 			if (!RBRQ_HBUF_ERR(he_dev->rbrq_head))
@@ -1966,6 +1947,7 @@
 					RBRQ_MASK(++he_dev->rbrq_head));
 
 	}
+	read_unlock(&vcc_sklist_lock);
 
 	if (updated) {
 		if (updated > he_dev->rbrq_peak)
@@ -2565,10 +2547,6 @@
 #endif
 
 		spin_unlock_irqrestore(&he_dev->global_lock, flags);
-
-#ifndef USE_HE_FIND_VCC
-		HE_LOOKUP_VCC(he_dev, cid) = vcc;
-#endif
 	}
 
 open_failed:
@@ -2634,9 +2612,6 @@
 		if (timeout == 0)
 			hprintk("close rx timeout cid 0x%x\n", cid);
 
-#ifndef USE_HE_FIND_VCC
-		HE_LOOKUP_VCC(he_dev, cid) = NULL;
-#endif
 		HPRINTK("close rx cid 0x%x complete\n", cid);
 
 	}
diff -Nru a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
--- a/drivers/atm/idt77252.c	Wed Jun 18 11:19:12 2003
+++ b/drivers/atm/idt77252.c	Wed Jun 18 11:19:12 2003
@@ -2403,37 +2403,43 @@
 static int
 idt77252_find_vcc(struct atm_vcc *vcc, short *vpi, int *vci)
 {
-	unsigned long flags;
+	struct sock *s;
 	struct atm_vcc *walk;
 
-	spin_lock_irqsave(&vcc->dev->lock, flags);
+	read_lock(&vcc_sklist_lock);
 	if (*vpi == ATM_VPI_ANY) {
 		*vpi = 0;
-		walk = vcc->dev->vccs;
-		while (walk) {
+		s = sk_head(&vcc_sklist);
+		while (s) {
+			walk = atm_sk(s);
+			if (walk->dev != vcc->dev)
+				continue;
 			if ((walk->vci == *vci) && (walk->vpi == *vpi)) {
 				(*vpi)++;
-				walk = vcc->dev->vccs;
+				s = sk_head(&vcc_sklist);
 				continue;
 			}
-			walk = walk->next;
+			s = sk_next(s);
 		}
 	}
 
 	if (*vci == ATM_VCI_ANY) {
 		*vci = ATM_NOT_RSV_VCI;
-		walk = vcc->dev->vccs;
-		while (walk) {
+		s = sk_head(&vcc_sklist);
+		while (s) {
+			walk = atm_sk(s);
+			if (walk->dev != vcc->dev)
+				continue;
 			if ((walk->vci == *vci) && (walk->vpi == *vpi)) {
 				(*vci)++;
-				walk = vcc->dev->vccs;
+				s = sk_head(&vcc_sklist);
 				continue;
 			}
-			walk = walk->next;
+			s = sk_next(s);
 		}
 	}
 
-	spin_unlock_irqrestore(&vcc->dev->lock, flags);
+	read_unlock(&vcc_sklist_lock);
 	return 0;
 }
 
diff -Nru a/include/linux/atmdev.h b/include/linux/atmdev.h
--- a/include/linux/atmdev.h	Wed Jun 18 11:19:12 2003
+++ b/include/linux/atmdev.h	Wed Jun 18 11:19:12 2003
@@ -293,7 +293,6 @@
 	struct k_atm_aal_stats *stats;	/* pointer to AAL stats group */
 	wait_queue_head_t sleep;	/* if socket is busy */
 	struct sock	*sk;		/* socket backpointer */
-	struct atm_vcc	*prev,*next;
 	/* SVC part --- may move later ------------------------------------- */
 	short		itf;		/* interface number */
 	struct sockaddr_atmsvc local;
@@ -320,8 +319,6 @@
 					/* (NULL) */
 	const char	*type;		/* device type name */
 	int		number;		/* device index */
-	struct atm_vcc	*vccs;		/* VCC table (or NULL) */
-	struct atm_vcc	*last;		/* last VCC (or undefined) */
 	void		*dev_data;	/* per-device data */
 	void		*phy_data;	/* private PHY date */
 	unsigned long	flags;		/* device flags (ATM_DF_*) */
@@ -390,6 +387,9 @@
 	unsigned long	atm_options;	/* ATM layer options */
 };
 
+extern struct hlist_head vcc_sklist;
+extern rwlock_t vcc_sklist_lock;
+
 #define ATM_SKB(skb) (((struct atm_skb_data *) (skb)->cb))
 
 struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
@@ -397,7 +397,8 @@
 struct atm_dev *atm_dev_lookup(int number);
 void atm_dev_deregister(struct atm_dev *dev);
 void shutdown_atm_dev(struct atm_dev *dev);
-void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev);
+void vcc_insert_socket(struct sock *sk);
+void vcc_remove_socket(struct sock *sk);
 
 
 /*
@@ -436,7 +437,7 @@
 }
 
 
-static inline void atm_dev_release(struct atm_dev *dev)
+static inline void atm_dev_put(struct atm_dev *dev)
 {
 	atomic_dec(&dev->refcnt);
 
diff -Nru a/net/atm/atm_misc.c b/net/atm/atm_misc.c
--- a/net/atm/atm_misc.c	Wed Jun 18 11:19:12 2003
+++ b/net/atm/atm_misc.c	Wed Jun 18 11:19:12 2003
@@ -47,15 +47,21 @@
 
 static int check_ci(struct atm_vcc *vcc,short vpi,int vci)
 {
+	struct hlist_node *node;
+	struct sock *s;
 	struct atm_vcc *walk;
 
-	for (walk = vcc->dev->vccs; walk; walk = walk->next)
+	sk_for_each(s, node, &vcc_sklist) {
+		walk = atm_sk(s);
+		if (walk->dev != vcc->dev)
+			continue;
 		if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vpi == vpi &&
 		    walk->vci == vci && ((walk->qos.txtp.traffic_class !=
 		    ATM_NONE && vcc->qos.txtp.traffic_class != ATM_NONE) ||
 		    (walk->qos.rxtp.traffic_class != ATM_NONE &&
 		    vcc->qos.rxtp.traffic_class != ATM_NONE)))
 			return -EADDRINUSE;
+	}
 		/* allow VCCs with same VPI/VCI iff they don't collide on
 		   TX/RX (but we may refuse such sharing for other reasons,
 		   e.g. if protocol requires to have both channels) */
@@ -65,17 +71,16 @@
 
 int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci)
 {
-	unsigned long flags;
 	static short p = 0; /* poor man's per-device cache */
 	static int c = 0;
 	short old_p;
 	int old_c;
 	int err;
 
-	spin_lock_irqsave(&vcc->dev->lock, flags);
+	read_lock(&vcc_sklist_lock);
 	if (*vpi != ATM_VPI_ANY && *vci != ATM_VCI_ANY) {
 		err = check_ci(vcc,*vpi,*vci);
-		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		read_unlock(&vcc_sklist_lock);
 		return err;
 	}
 	/* last scan may have left values out of bounds for current device */
@@ -90,7 +95,7 @@
 		if (!check_ci(vcc,p,c)) {
 			*vpi = p;
 			*vci = c;
-			spin_unlock_irqrestore(&vcc->dev->lock, flags);
+			read_unlock(&vcc_sklist_lock);
 			return 0;
 		}
 		if (*vci == ATM_VCI_ANY) {
@@ -105,7 +110,7 @@
 		}
 	}
 	while (old_p != p || old_c != c);
-	spin_unlock_irqrestore(&vcc->dev->lock, flags);
+	read_unlock(&vcc_sklist_lock);
 	return -EADDRINUSE;
 }
 
diff -Nru a/net/atm/clip.c b/net/atm/clip.c
--- a/net/atm/clip.c	Wed Jun 18 11:19:12 2003
+++ b/net/atm/clip.c	Wed Jun 18 11:19:12 2003
@@ -737,7 +737,8 @@
 	set_bit(ATM_VF_META,&vcc->flags);
 	set_bit(ATM_VF_READY,&vcc->flags);
 	    /* allow replies and avoid getting closed if signaling dies */
-	bind_vcc(vcc,&atmarpd_dev);
+	vcc->dev = &atmarpd_dev;
+	vcc_insert_socket(vcc->sk);
 	vcc->push = NULL;
 	vcc->pop = NULL; /* crash */
 	vcc->push_oam = NULL; /* crash */
diff -Nru a/net/atm/common.c b/net/atm/common.c
--- a/net/atm/common.c	Wed Jun 18 11:19:12 2003
+++ b/net/atm/common.c	Wed Jun 18 11:19:12 2003
@@ -157,6 +157,29 @@
 #endif
 
 
+HLIST_HEAD(vcc_sklist);
+rwlock_t vcc_sklist_lock = RW_LOCK_UNLOCKED;
+
+void __vcc_insert_socket(struct sock *sk)
+{
+	sk_add_node(sk, &vcc_sklist);
+}
+
+void vcc_insert_socket(struct sock *sk)
+{
+	write_lock_irq(&vcc_sklist_lock);
+	__vcc_insert_socket(sk);
+	write_unlock_irq(&vcc_sklist_lock);
+}
+
+void vcc_remove_socket(struct sock *sk)
+{
+	write_lock_irq(&vcc_sklist_lock);
+	sk_del_node_init(sk);
+	write_unlock_irq(&vcc_sklist_lock);
+}
+
+
 static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
 {
 	struct sk_buff *skb;
@@ -175,16 +198,45 @@
 }
 
 
-int atm_create(struct socket *sock,int protocol,int family)
+EXPORT_SYMBOL(vcc_sklist);
+EXPORT_SYMBOL(vcc_sklist_lock);
+EXPORT_SYMBOL(vcc_insert_socket);
+EXPORT_SYMBOL(vcc_remove_socket);
+
+static void vcc_sock_destruct(struct sock *sk)
+{
+	struct atm_vcc *vcc = atm_sk(sk);
+
+	if (atomic_read(&vcc->sk->sk_rmem_alloc))
+		printk(KERN_DEBUG "vcc_sock_destruct: rmem leakage (%d bytes) detected.\n", atomic_read(&sk->sk_rmem_alloc));
+
+	if (atomic_read(&vcc->sk->sk_wmem_alloc))
+		printk(KERN_DEBUG "vcc_sock_destruct: wmem leakage (%d bytes) detected.\n", atomic_read(&sk->sk_wmem_alloc));
+
+	kfree(sk->sk_protinfo);
+}
+ 
+int vcc_create(struct socket *sock, int protocol, int family)
 {
 	struct sock *sk;
 	struct atm_vcc *vcc;
 
 	sock->sk = NULL;
-	if (sock->type == SOCK_STREAM) return -EINVAL;
-	if (!(sk = alloc_atm_vcc_sk(family))) return -ENOMEM;
-	vcc = atm_sk(sk);
-	memset(&vcc->flags,0,sizeof(vcc->flags));
+	if (sock->type == SOCK_STREAM)
+		return -EINVAL;
+	sk = sk_alloc(family, GFP_KERNEL, 1, NULL);
+	if (!sk)
+		return -ENOMEM;
+	sock_init_data(NULL, sk);
+
+	vcc = atm_sk(sk) = kmalloc(sizeof(*vcc), GFP_KERNEL);
+	if (!vcc) {
+		sk_free(sk);
+		return -ENOMEM;
+	}
+
+	memset(vcc, 0, sizeof(*vcc));
+	vcc->sk = sk;
 	vcc->dev = NULL;
 	vcc->callback = NULL;
 	memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc));
@@ -199,42 +251,49 @@
 	vcc->atm_options = vcc->aal_options = 0;
 	init_waitqueue_head(&vcc->sleep);
 	sk->sk_sleep = &vcc->sleep;
+	sk->sk_destruct = vcc_sock_destruct;
 	sock->sk = sk;
 	return 0;
 }
 
 
-void atm_release_vcc_sk(struct sock *sk,int free_sk)
+static void vcc_destroy_socket(struct sock *sk)
 {
 	struct atm_vcc *vcc = atm_sk(sk);
 	struct sk_buff *skb;
 
-	clear_bit(ATM_VF_READY,&vcc->flags);
+	clear_bit(ATM_VF_READY, &vcc->flags);
 	if (vcc->dev) {
-		if (vcc->dev->ops->close) vcc->dev->ops->close(vcc);
-		if (vcc->push) vcc->push(vcc,NULL); /* atmarpd has no push */
+		if (vcc->dev->ops->close)
+			vcc->dev->ops->close(vcc);
+		if (vcc->push)
+			vcc->push(vcc, NULL); /* atmarpd has no push */
+
+		vcc_remove_socket(sk);	/* no more receive */
+
 		while ((skb = skb_dequeue(&vcc->sk->sk_receive_queue))) {
 			atm_return(vcc,skb->truesize);
 			kfree_skb(skb);
 		}
 
 		module_put(vcc->dev->ops->owner);
-		atm_dev_release(vcc->dev);
-		if (atomic_read(&vcc->sk->sk_rmem_alloc))
-			printk(KERN_WARNING "atm_release_vcc: strange ... "
-			    "rmem_alloc == %d after closing\n",
-			    atomic_read(&vcc->sk->sk_rmem_alloc));
-		bind_vcc(vcc,NULL);
+		atm_dev_put(vcc->dev);
 	}
-
-	if (free_sk) free_atm_vcc_sk(sk);
 }
 
 
-int atm_release(struct socket *sock)
+int vcc_release(struct socket *sock)
 {
-	if (sock->sk)
-		atm_release_vcc_sk(sock->sk,1);
+	struct sock *sk = sock->sk;
+
+	if (sk) {
+		sock_orphan(sk);
+		lock_sock(sk);
+		vcc_destroy_socket(sock->sk);
+		release_sock(sk);
+		sock_put(sk);
+	}
+
 	return 0;
 }
 
@@ -289,7 +348,8 @@
 	if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE))
 		return -EPERM;
 	error = 0;
-	bind_vcc(vcc,dev);
+	vcc->dev = dev;
+	vcc_insert_socket(vcc->sk);
 	switch (vcc->qos.aal) {
 		case ATM_AAL0:
 			error = atm_init_aal0(vcc);
@@ -313,7 +373,7 @@
 	if (!error) error = adjust_tp(&vcc->qos.txtp,vcc->qos.aal);
 	if (!error) error = adjust_tp(&vcc->qos.rxtp,vcc->qos.aal);
 	if (error) {
-		bind_vcc(vcc,NULL);
+		vcc_remove_socket(vcc->sk);
 		return error;
 	}
 	DPRINTK("VCC %d.%d, AAL %d\n",vpi,vci,vcc->qos.aal);
@@ -327,7 +387,7 @@
 		error = dev->ops->open(vcc,vpi,vci);
 		if (error) {
 			module_put(dev->ops->owner);
-			bind_vcc(vcc,NULL);
+			vcc_remove_socket(vcc->sk);
 			return error;
 		}
 	}
@@ -371,7 +431,7 @@
 		dev = atm_dev_lookup(itf);
 		error = __vcc_connect(vcc, dev, vpi, vci);
 		if (error) {
-			atm_dev_release(dev);
+			atm_dev_put(dev);
 			return error;
 		}
 	} else {
@@ -385,7 +445,7 @@
 			spin_unlock(&atm_dev_lock);
 			if (!__vcc_connect(vcc, dev, vpi, vci))
 				break;
-			atm_dev_release(dev);
+			atm_dev_put(dev);
 			dev = NULL;
 			spin_lock(&atm_dev_lock);
 		}
diff -Nru a/net/atm/common.h b/net/atm/common.h
--- a/net/atm/common.h	Wed Jun 18 11:19:12 2003
+++ b/net/atm/common.h	Wed Jun 18 11:19:12 2003
@@ -10,8 +10,8 @@
 #include <linux/poll.h> /* for poll_table */
 
 
-int atm_create(struct socket *sock,int protocol,int family);
-int atm_release(struct socket *sock);
+int vcc_create(struct socket *sock, int protocol, int family);
+int vcc_release(struct socket *sock);
 int vcc_connect(struct socket *sock, int itf, short vpi, int vci);
 int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
 		int size, int flags);
@@ -24,7 +24,6 @@
 int vcc_getsockopt(struct socket *sock, int level, int optname, char *optval,
 		   int *optlen);
 
-void atm_release_vcc_sk(struct sock *sk,int free_sk);
 void atm_shutdown_dev(struct atm_dev *dev);
 
 int atmpvc_init(void);
diff -Nru a/net/atm/lec.c b/net/atm/lec.c
--- a/net/atm/lec.c	Wed Jun 18 11:19:12 2003
+++ b/net/atm/lec.c	Wed Jun 18 11:19:12 2003
@@ -48,7 +48,7 @@
 
 #include "lec.h"
 #include "lec_arpc.h"
-#include "resources.h"  /* for bind_vcc() */
+#include "resources.h"
 
 #if 0
 #define DPRINTK printk
@@ -810,7 +810,8 @@
         lec_arp_init(priv);
 	priv->itfnum = i;  /* LANE2 addition */
         priv->lecd = vcc;
-        bind_vcc(vcc, &lecatm_dev);
+        vcc->dev = &lecatm_dev;
+        vcc_insert_socket(vcc->sk);
         
         vcc->proto_data = dev_lec[i];
 	set_bit(ATM_VF_META,&vcc->flags);
diff -Nru a/net/atm/mpc.c b/net/atm/mpc.c
--- a/net/atm/mpc.c	Wed Jun 18 11:19:12 2003
+++ b/net/atm/mpc.c	Wed Jun 18 11:19:12 2003
@@ -28,7 +28,7 @@
 
 #include "lec.h"
 #include "mpc.h"
-#include "resources.h"  /* for bind_vcc() */
+#include "resources.h"
 
 /*
  * mpc.c: Implementation of MPOA client kernel part 
@@ -789,7 +789,8 @@
 	}
 
 	mpc->mpoad_vcc = vcc;
-	bind_vcc(vcc, &mpc_dev);
+	vcc->dev = &mpc_dev;
+	vcc_insert_socket(vcc->sk);
 	set_bit(ATM_VF_META,&vcc->flags);
 	set_bit(ATM_VF_READY,&vcc->flags);
 
diff -Nru a/net/atm/proc.c b/net/atm/proc.c
--- a/net/atm/proc.c	Wed Jun 18 11:19:12 2003
+++ b/net/atm/proc.c	Wed Jun 18 11:19:12 2003
@@ -334,9 +334,8 @@
 
 static int atm_pvc_info(loff_t pos,char *buf)
 {
-	unsigned long flags;
-	struct atm_dev *dev;
-	struct list_head *p;
+	struct hlist_node *node;
+	struct sock *s;
 	struct atm_vcc *vcc;
 	int left, clip_info = 0;
 
@@ -349,25 +348,20 @@
 	if (try_atm_clip_ops())
 		clip_info = 1;
 #endif
-	spin_lock(&atm_dev_lock);
-	list_for_each(p, &atm_devs) {
-		dev = list_entry(p, struct atm_dev, dev_list);
-		spin_lock_irqsave(&dev->lock, flags);
-		for (vcc = dev->vccs; vcc; vcc = vcc->next)
-			if (vcc->sk->sk_family == PF_ATMPVC &&
-			    vcc->dev && !left--) {
-				pvc_info(vcc,buf,clip_info);
-				spin_unlock_irqrestore(&dev->lock, flags);
-				spin_unlock(&atm_dev_lock);
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+		vcc = atm_sk(s);
+		if (vcc->sk->sk_family == PF_ATMPVC && vcc->dev && !left--) {
+			pvc_info(vcc,buf,clip_info);
+			read_unlock(&vcc_sklist_lock);
 #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
-				if (clip_info)
-					module_put(atm_clip_ops->owner);
+			if (clip_info)
+				module_put(atm_clip_ops->owner);
 #endif
-				return strlen(buf);
-			}
-		spin_unlock_irqrestore(&dev->lock, flags);
+			return strlen(buf);
+		}
 	}
-	spin_unlock(&atm_dev_lock);
+	read_unlock(&vcc_sklist_lock);
 #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
 	if (clip_info)
 		module_put(atm_clip_ops->owner);
@@ -378,10 +372,9 @@
 
 static int atm_vc_info(loff_t pos,char *buf)
 {
-	unsigned long flags;
-	struct atm_dev *dev;
-	struct list_head *p;
 	struct atm_vcc *vcc;
+	struct hlist_node *node;
+	struct sock *s;
 	int left;
 
 	if (!pos)
@@ -389,20 +382,16 @@
 		    "Address"," Itf VPI VCI   Fam Flags Reply Send buffer"
 		    "     Recv buffer\n");
 	left = pos-1;
-	spin_lock(&atm_dev_lock);
-	list_for_each(p, &atm_devs) {
-		dev = list_entry(p, struct atm_dev, dev_list);
-		spin_lock_irqsave(&dev->lock, flags);
-		for (vcc = dev->vccs; vcc; vcc = vcc->next)
-			if (!left--) {
-				vc_info(vcc,buf);
-				spin_unlock_irqrestore(&dev->lock, flags);
-				spin_unlock(&atm_dev_lock);
-				return strlen(buf);
-			}
-		spin_unlock_irqrestore(&dev->lock, flags);
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+		vcc = atm_sk(s);
+		if (!left--) {
+			vc_info(vcc,buf);
+			read_unlock(&vcc_sklist_lock);
+			return strlen(buf);
+		}
 	}
-	spin_unlock(&atm_dev_lock);
+	read_unlock(&vcc_sklist_lock);
 
 	return 0;
 }
@@ -410,29 +399,24 @@
 
 static int atm_svc_info(loff_t pos,char *buf)
 {
-	unsigned long flags;
-	struct atm_dev *dev;
-	struct list_head *p;
+	struct hlist_node *node;
+	struct sock *s;
 	struct atm_vcc *vcc;
 	int left;
 
 	if (!pos)
 		return sprintf(buf,"Itf VPI VCI           State      Remote\n");
 	left = pos-1;
-	spin_lock(&atm_dev_lock);
-	list_for_each(p, &atm_devs) {
-		dev = list_entry(p, struct atm_dev, dev_list);
-		spin_lock_irqsave(&dev->lock, flags);
-		for (vcc = dev->vccs; vcc; vcc = vcc->next)
-			if (vcc->sk->sk_family == PF_ATMSVC && !left--) {
-				svc_info(vcc,buf);
-				spin_unlock_irqrestore(&dev->lock, flags);
-				spin_unlock(&atm_dev_lock);
-				return strlen(buf);
-			}
-		spin_unlock_irqrestore(&dev->lock, flags);
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+		vcc = atm_sk(s);
+		if (vcc->sk->sk_family == PF_ATMSVC && !left--) {
+			svc_info(vcc,buf);
+			read_unlock(&vcc_sklist_lock);
+			return strlen(buf);
+		}
 	}
-	spin_unlock(&atm_dev_lock);
+	read_unlock(&vcc_sklist_lock);
 
 	return 0;
 }
diff -Nru a/net/atm/pvc.c b/net/atm/pvc.c
--- a/net/atm/pvc.c	Wed Jun 18 11:19:12 2003
+++ b/net/atm/pvc.c	Wed Jun 18 11:19:12 2003
@@ -17,10 +17,6 @@
 #include "resources.h"		/* devs and vccs */
 #include "common.h"		/* common for PVCs and SVCs */
 
-#ifndef NULL
-#define NULL 0
-#endif
-
 
 static int pvc_shutdown(struct socket *sock,int how)
 {
@@ -109,7 +105,7 @@
 static struct proto_ops pvc_proto_ops = {
 	.family =	PF_ATMPVC,
 
-	.release =	atm_release,
+	.release =	vcc_release,
 	.bind =		pvc_bind,
 	.connect =	pvc_connect,
 	.socketpair =	sock_no_socketpair,
@@ -131,7 +127,7 @@
 static int pvc_create(struct socket *sock,int protocol)
 {
 	sock->ops = &pvc_proto_ops;
-	return atm_create(sock,protocol,PF_ATMPVC);
+	return vcc_create(sock, protocol, PF_ATMPVC);
 }
 
 
diff -Nru a/net/atm/resources.c b/net/atm/resources.c
--- a/net/atm/resources.c	Wed Jun 18 11:19:12 2003
+++ b/net/atm/resources.c	Wed Jun 18 11:19:12 2003
@@ -23,11 +23,6 @@
 #include "addr.h"
 
 
-#ifndef NULL
-#define NULL 0
-#endif
-
-
 LIST_HEAD(atm_devs);
 spinlock_t atm_dev_lock = SPIN_LOCK_UNLOCKED;
 
@@ -91,7 +86,7 @@
 	spin_lock(&atm_dev_lock);
 	if (number != -1) {
 		if ((inuse = __atm_dev_lookup(number))) {
-			atm_dev_release(inuse);
+			atm_dev_put(inuse);
 			spin_unlock(&atm_dev_lock);
 			__free_atm_dev(dev);
 			return NULL;
@@ -100,7 +95,7 @@
 	} else {
 		dev->number = 0;
 		while ((inuse = __atm_dev_lookup(dev->number))) {
-			atm_dev_release(inuse);
+			atm_dev_put(inuse);
 			dev->number++;
 		}
 	}
@@ -402,78 +397,12 @@
 	else
 		error = 0;
 done:
-	atm_dev_release(dev);
+	atm_dev_put(dev);
 	return error;
 }
 
 
-struct sock *alloc_atm_vcc_sk(int family)
-{
-	struct sock *sk;
-	struct atm_vcc *vcc;
-
-	sk = sk_alloc(family, GFP_KERNEL, 1, NULL);
-	if (!sk)
-		return NULL;
-	vcc = atm_sk(sk) = kmalloc(sizeof(*vcc), GFP_KERNEL);
-	if (!vcc) {
-		sk_free(sk);
-		return NULL;
-	}
-	sock_init_data(NULL, sk);
-	memset(vcc, 0, sizeof(*vcc));
-	vcc->sk = sk;
-
-	return sk;
-}
-
-
-static void unlink_vcc(struct atm_vcc *vcc)
-{
-	unsigned long flags;
-	if (vcc->dev) {
-		spin_lock_irqsave(&vcc->dev->lock, flags);
-		if (vcc->prev)
-			vcc->prev->next = vcc->next;
-		else
-			vcc->dev->vccs = vcc->next;
-
-		if (vcc->next)
-			vcc->next->prev = vcc->prev;
-		else
-			vcc->dev->last = vcc->prev;
-		spin_unlock_irqrestore(&vcc->dev->lock, flags);
-	}
-}
-
-
-void free_atm_vcc_sk(struct sock *sk)
-{
-	unlink_vcc(atm_sk(sk));
-	sk_free(sk);
-}
-
-void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev)
-{
-	unsigned long flags;
-
-	unlink_vcc(vcc);
-	vcc->dev = dev;
-	if (dev) {
-		spin_lock_irqsave(&dev->lock, flags);
-		vcc->next = NULL;
-		vcc->prev = dev->last;
-		if (dev->vccs)
-			dev->last->next = vcc;
-		else
-			dev->vccs = vcc;
-		dev->last = vcc;
-		spin_unlock_irqrestore(&dev->lock, flags);
-	}
-}
-
 EXPORT_SYMBOL(atm_dev_register);
 EXPORT_SYMBOL(atm_dev_deregister);
 EXPORT_SYMBOL(atm_dev_lookup);
 EXPORT_SYMBOL(shutdown_atm_dev);
-EXPORT_SYMBOL(bind_vcc);
diff -Nru a/net/atm/resources.h b/net/atm/resources.h
--- a/net/atm/resources.h	Wed Jun 18 11:19:12 2003
+++ b/net/atm/resources.h	Wed Jun 18 11:19:12 2003
@@ -14,8 +14,6 @@
 extern spinlock_t atm_dev_lock;
 
 
-struct sock *alloc_atm_vcc_sk(int family);
-void free_atm_vcc_sk(struct sock *sk);
 int atm_dev_ioctl(unsigned int cmd, unsigned long arg);
 
 
diff -Nru a/net/atm/signaling.c b/net/atm/signaling.c
--- a/net/atm/signaling.c	Wed Jun 18 11:19:12 2003
+++ b/net/atm/signaling.c	Wed Jun 18 11:19:12 2003
@@ -200,26 +200,22 @@
 }
 
 
-static void purge_vccs(struct atm_vcc *vcc)
+static void purge_vcc(struct atm_vcc *vcc)
 {
-	while (vcc) {
-		if (vcc->sk->sk_family == PF_ATMSVC &&
-		    !test_bit(ATM_VF_META,&vcc->flags)) {
-			set_bit(ATM_VF_RELEASED,&vcc->flags);
-			vcc->reply = -EUNATCH;
-			vcc->sk->sk_err = EUNATCH;
-			wake_up(&vcc->sleep);
-		}
-		vcc = vcc->next;
+	if (vcc->sk->sk_family == PF_ATMSVC &&
+	    !test_bit(ATM_VF_META,&vcc->flags)) {
+		set_bit(ATM_VF_RELEASED,&vcc->flags);
+		vcc->reply = -EUNATCH;
+		vcc->sk->sk_err = EUNATCH;
+		wake_up(&vcc->sleep);
 	}
 }
 
 
 static void sigd_close(struct atm_vcc *vcc)
 {
-	unsigned long flags;
-	struct atm_dev *dev;
-	struct list_head *p;
+	struct hlist_node *node;
+	struct sock *s;
 
 	DPRINTK("sigd_close\n");
 	sigd = NULL;
@@ -227,14 +223,14 @@
 		printk(KERN_ERR "sigd_close: closing with requests pending\n");
 	skb_queue_purge(&vcc->sk->sk_receive_queue);
 
-	spin_lock(&atm_dev_lock);
-	list_for_each(p, &atm_devs) {
-		dev = list_entry(p, struct atm_dev, dev_list);
-		spin_lock_irqsave(&dev->lock, flags);
-		purge_vccs(dev->vccs);
-		spin_unlock_irqrestore(&dev->lock, flags);
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+		struct atm_vcc *vcc = atm_sk(s);
+
+		if (vcc->dev)
+			purge_vcc(vcc);
 	}
-	spin_unlock(&atm_dev_lock);
+	read_unlock(&vcc_sklist_lock);
 }
 
 
@@ -257,7 +253,8 @@
 	if (sigd) return -EADDRINUSE;
 	DPRINTK("sigd_attach\n");
 	sigd = vcc;
-	bind_vcc(vcc,&sigd_dev);
+	vcc->dev = &sigd_dev;
+	vcc_insert_socket(vcc->sk);
 	set_bit(ATM_VF_META,&vcc->flags);
 	set_bit(ATM_VF_READY,&vcc->flags);
 	wake_up(&sigd_sleep);
diff -Nru a/net/atm/svc.c b/net/atm/svc.c
--- a/net/atm/svc.c	Wed Jun 18 11:19:12 2003
+++ b/net/atm/svc.c	Wed Jun 18 11:19:12 2003
@@ -88,18 +88,21 @@
 
 static int svc_release(struct socket *sock)
 {
+	struct sock *sk = sock->sk;
 	struct atm_vcc *vcc;
 
-	if (!sock->sk) return 0;
-	vcc = ATM_SD(sock);
-	DPRINTK("svc_release %p\n",vcc);
-	clear_bit(ATM_VF_READY,&vcc->flags);
-	atm_release_vcc_sk(sock->sk,0);
-	svc_disconnect(vcc);
-	    /* VCC pointer is used as a reference, so we must not free it
-	       (thereby subjecting it to re-use) before all pending connections
-	        are closed */
-	free_atm_vcc_sk(sock->sk);
+	if (sk)  {
+		vcc = ATM_SD(sock);
+		DPRINTK("svc_release %p\n", vcc);
+		clear_bit(ATM_VF_READY, &vcc->flags);
+		/* VCC pointer is used as a reference, so we must not free it
+		   (thereby subjecting it to re-use) before all pending connections
+	           are closed */
+		sock_hold(sk);
+		vcc_release(sock);
+		svc_disconnect(vcc);
+		sock_put(sk);
+	}
 	return 0;
 }
 
@@ -542,7 +545,7 @@
 	int error;
 
 	sock->ops = &svc_proto_ops;
-	error = atm_create(sock,protocol,AF_ATMSVC);
+	error = vcc_create(sock, protocol, AF_ATMSVC);
 	if (error) return error;
 	ATM_SD(sock)->callback = svc_callback;
 	ATM_SD(sock)->local.sas_family = AF_ATMSVC;

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

* Re: [PATCH][ATM][3/3] assorted changes for atm
  2003-06-17 17:31 ` David S. Miller
  2003-06-18 15:24   ` chas williams
@ 2003-06-20 20:53   ` chas williams
  2003-06-20 21:32     ` chas williams
  1 sibling, 1 reply; 5+ messages in thread
From: chas williams @ 2003-06-20 20:53 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev

here is yet another version of the vcc sklist conversion.  thanks
to acme@conectiva.com.br for pointing out my brain damage about
testing the iterator during list traversal.

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.1359  -> 1.1360 
#	    drivers/atm/he.c	1.15    -> 1.16   
#	  net/atm/atm_misc.c	1.7     -> 1.8    
#	   drivers/atm/eni.c	1.17    -> 1.18   
#	      net/atm/proc.c	1.20    -> 1.21   
#	       net/atm/pvc.c	1.16    -> 1.17   
#	drivers/atm/idt77252.c	1.17    -> 1.18   
#	       net/atm/lec.c	1.29    -> 1.30   
#	drivers/atm/atmtcp.c	1.10    -> 1.11   
#	       net/atm/svc.c	1.18    -> 1.19   
#	    net/atm/common.h	1.12    -> 1.13   
#	 net/atm/signaling.c	1.14    -> 1.15   
#	 net/atm/resources.h	1.7     -> 1.8    
#	       net/atm/mpc.c	1.20    -> 1.21   
#	 net/atm/resources.c	1.13    -> 1.14   
#	      net/atm/clip.c	1.17    -> 1.18   
#	drivers/atm/fore200e.c	1.18    -> 1.19   
#	    net/atm/common.c	1.35    -> 1.36   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/06/20	chas@relax.cmf.nrl.navy.mil	1.1360
# move vcc's to global sk-based linked list
# --------------------------------------------
#
diff -Nru a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c
--- a/drivers/atm/atmtcp.c	Fri Jun 20 16:53:20 2003
+++ b/drivers/atm/atmtcp.c	Fri Jun 20 16:53:20 2003
@@ -153,9 +153,10 @@
 
 static int atmtcp_v_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
 {
-	unsigned long flags;
 	struct atm_cirange ci;
 	struct atm_vcc *vcc;
+	struct hlist_node *node;
+	struct sock *s;
 
 	if (cmd != ATM_SETCIRANGE) return -ENOIOCTLCMD;
 	if (copy_from_user(&ci,(void *) arg,sizeof(ci))) return -EFAULT;
@@ -163,14 +164,18 @@
 	if (ci.vci_bits == ATM_CI_MAX) ci.vci_bits = MAX_VCI_BITS;
 	if (ci.vpi_bits > MAX_VPI_BITS || ci.vpi_bits < 0 ||
 	    ci.vci_bits > MAX_VCI_BITS || ci.vci_bits < 0) return -EINVAL;
-	spin_lock_irqsave(&dev->lock, flags);
-	for (vcc = dev->vccs; vcc; vcc = vcc->next)
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+		vcc = atm_sk(s);
+		if (vcc->dev != dev)
+			continue;
 		if ((vcc->vpi >> ci.vpi_bits) ||
 		    (vcc->vci >> ci.vci_bits)) {
-			spin_unlock_irqrestore(&dev->lock, flags);
+			read_unlock(&vcc_sklist_lock);
 			return -EBUSY;
 		}
-	spin_unlock_irqrestore(&dev->lock, flags);
+	}
+	read_unlock(&vcc_sklist_lock);
 	dev->ci_range = ci;
 	return 0;
 }
@@ -233,9 +238,10 @@
 
 static void atmtcp_c_close(struct atm_vcc *vcc)
 {
-	unsigned long flags;
 	struct atm_dev *atmtcp_dev;
 	struct atmtcp_dev_data *dev_data;
+	struct sock *s;
+	struct hlist_node *node;
 	struct atm_vcc *walk;
 
 	atmtcp_dev = (struct atm_dev *) vcc->dev_data;
@@ -246,19 +252,24 @@
 	kfree(dev_data);
 	shutdown_atm_dev(atmtcp_dev);
 	vcc->dev_data = NULL;
-	spin_lock_irqsave(&atmtcp_dev->lock, flags);
-	for (walk = atmtcp_dev->vccs; walk; walk = walk->next)
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+		walk = atm_sk(s);
+		if (walk->dev != atmtcp_dev)
+			continue;
 		wake_up(&walk->sleep);
-	spin_unlock_irqrestore(&atmtcp_dev->lock, flags);
+	}
+	read_unlock(&vcc_sklist_lock);
 }
 
 
 static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb)
 {
-	unsigned long flags;
 	struct atm_dev *dev;
 	struct atmtcp_hdr *hdr;
-	struct atm_vcc *out_vcc;
+	struct sock *s;
+	struct hlist_node *node;
+	struct atm_vcc *out_vcc = NULL;
 	struct sk_buff *new_skb;
 	int result = 0;
 
@@ -270,13 +281,17 @@
 		    (struct atmtcp_control *) skb->data);
 		goto done;
 	}
-	spin_lock_irqsave(&dev->lock, flags);
-	for (out_vcc = dev->vccs; out_vcc; out_vcc = out_vcc->next)
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+		out_vcc = atm_sk(s);
+		if (out_vcc->dev != dev)
+			continue;
 		if (out_vcc->vpi == ntohs(hdr->vpi) &&
 		    out_vcc->vci == ntohs(hdr->vci) &&
 		    out_vcc->qos.rxtp.traffic_class != ATM_NONE)
 			break;
-	spin_unlock_irqrestore(&dev->lock, flags);
+	}
+	read_unlock(&vcc_sklist_lock);
 	if (!out_vcc) {
 		atomic_inc(&vcc->stats->tx_err);
 		goto done;
@@ -366,7 +381,7 @@
 	if (itf != -1) dev = atm_dev_lookup(itf);
 	if (dev) {
 		if (dev->ops != &atmtcp_v_dev_ops) {
-			atm_dev_release(dev);
+			atm_dev_put(dev);
 			return -EMEDIUMTYPE;
 		}
 		if (PRIV(dev)->vcc) return -EBUSY;
@@ -378,7 +393,8 @@
 		if (error) return error;
 	}
 	PRIV(dev)->vcc = vcc;
-	bind_vcc(vcc,&atmtcp_control_dev);
+	vcc->dev = &atmtcp_control_dev;
+	vcc_insert_socket(vcc->sk);
 	set_bit(ATM_VF_META,&vcc->flags);
 	set_bit(ATM_VF_READY,&vcc->flags);
 	vcc->dev_data = dev;
@@ -402,7 +418,7 @@
 	dev = atm_dev_lookup(itf);
 	if (!dev) return -ENODEV;
 	if (dev->ops != &atmtcp_v_dev_ops) {
-		atm_dev_release(dev);
+		atm_dev_put(dev);
 		return -EMEDIUMTYPE;
 	}
 	dev_data = PRIV(dev);
@@ -410,7 +426,7 @@
 	dev_data->persist = 0;
 	if (PRIV(dev)->vcc) return 0;
 	kfree(dev_data);
-	atm_dev_release(dev);
+	atm_dev_put(dev);
 	shutdown_atm_dev(dev);
 	return 0;
 }
diff -Nru a/drivers/atm/eni.c b/drivers/atm/eni.c
--- a/drivers/atm/eni.c	Fri Jun 20 16:53:20 2003
+++ b/drivers/atm/eni.c	Fri Jun 20 16:53:20 2003
@@ -1887,10 +1887,11 @@
 
 static int get_ci(struct atm_vcc *vcc,short *vpi,int *vci)
 {
-	unsigned long flags;
+	struct sock *s;
+	struct hlist_node *node;
 	struct atm_vcc *walk;
 
-	spin_lock_irqsave(&vcc->dev->lock, flags);
+	read_lock(&vcc_sklist_lock);
 	if (*vpi == ATM_VPI_ANY) *vpi = 0;
 	if (*vci == ATM_VCI_ANY) {
 		for (*vci = ATM_NOT_RSV_VCI; *vci < NR_VCI; (*vci)++) {
@@ -1898,40 +1899,48 @@
 			    ENI_DEV(vcc->dev)->rx_map[*vci])
 				continue;
 			if (vcc->qos.txtp.traffic_class != ATM_NONE) {
-				for (walk = vcc->dev->vccs; walk;
-				    walk = walk->next)
+				sk_for_each(s, node, &vcc_sklist) {
+					walk = atm_sk(s);
+					if (walk->dev != vcc->dev)
+						continue;
 					if (test_bit(ATM_VF_ADDR,&walk->flags)
 					    && walk->vci == *vci &&
 					    walk->qos.txtp.traffic_class !=
 					    ATM_NONE)
 						break;
-				if (walk) continue;
+				}
+				if (node)
+					continue;
 			}
 			break;
 		}
-		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		read_unlock(&vcc_sklist_lock);
 		return *vci == NR_VCI ? -EADDRINUSE : 0;
 	}
 	if (*vci == ATM_VCI_UNSPEC) {
-		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		read_unlock(&vcc_sklist_lock);
 		return 0;
 	}
 	if (vcc->qos.rxtp.traffic_class != ATM_NONE &&
 	    ENI_DEV(vcc->dev)->rx_map[*vci]) {
-		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		read_unlock(&vcc_sklist_lock);
 		return -EADDRINUSE;
 	}
 	if (vcc->qos.txtp.traffic_class == ATM_NONE) {
-		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		read_unlock(&vcc_sklist_lock);
 		return 0;
 	}
-	for (walk = vcc->dev->vccs; walk; walk = walk->next)
+	sk_for_each(s, node, &vcc_sklist) {
+		walk = atm_sk(s);
+		if (walk->dev != vcc->dev)
+			continue;
 		if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vci == *vci &&
 		    walk->qos.txtp.traffic_class != ATM_NONE) {
-			spin_unlock_irqrestore(&vcc->dev->lock, flags);
+			read_unlock(&vcc_sklist_lock);
 			return -EADDRINUSE;
 		}
-	spin_unlock_irqrestore(&vcc->dev->lock, flags);
+	}
+	read_unlock(&vcc_sklist_lock);
 	return 0;
 }
 
@@ -2139,7 +2148,8 @@
 
 static int eni_proc_read(struct atm_dev *dev,loff_t *pos,char *page)
 {
-	unsigned long flags;
+	struct hlist_node *node;
+	struct sock *s;
 	static const char *signal[] = { "LOST","unknown","okay" };
 	struct eni_dev *eni_dev = ENI_DEV(dev);
 	struct atm_vcc *vcc;
@@ -2212,11 +2222,15 @@
 		return sprintf(page,"%10sbacklog %u packets\n","",
 		    skb_queue_len(&tx->backlog));
 	}
-	spin_lock_irqsave(&dev->lock, flags);
-	for (vcc = dev->vccs; vcc; vcc = vcc->next) {
-		struct eni_vcc *eni_vcc = ENI_VCC(vcc);
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+		struct eni_vcc *eni_vcc;
 		int length;
 
+		vcc = atm_sk(s);
+		if (vcc->dev != dev)
+			continue;
+		eni_vcc = ENI_VCC(vcc);
 		if (--left) continue;
 		length = sprintf(page,"vcc %4d: ",vcc->vci);
 		if (eni_vcc->rx) {
@@ -2231,10 +2245,10 @@
 			length += sprintf(page+length,"tx[%d], txing %d bytes",
 			    eni_vcc->tx->index,eni_vcc->txing);
 		page[length] = '\n';
-		spin_unlock_irqrestore(&dev->lock, flags);
+		read_unlock(&vcc_sklist_lock);
 		return length+1;
 	}
-	spin_unlock_irqrestore(&dev->lock, flags);
+	read_unlock(&vcc_sklist_lock);
 	for (i = 0; i < eni_dev->free_len; i++) {
 		struct eni_free *fe = eni_dev->free_list+i;
 		unsigned long offset;
diff -Nru a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
--- a/drivers/atm/fore200e.c	Fri Jun 20 16:53:20 2003
+++ b/drivers/atm/fore200e.c	Fri Jun 20 16:53:20 2003
@@ -1069,18 +1069,23 @@
 static struct atm_vcc* 
 fore200e_find_vcc(struct fore200e* fore200e, struct rpd* rpd)
 {
-    unsigned long flags;
+    struct sock *s;
     struct atm_vcc* vcc;
+    struct hlist_node *node;
 
-    spin_lock_irqsave(&fore200e->atm_dev->lock, flags);
-    for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) {
-
-	if (vcc->vpi == rpd->atm_header.vpi && vcc->vci == rpd->atm_header.vci)
-	    break;
+    read_lock(&vcc_sklist_lock);
+    sk_for_each(s, node, &vcc_sklist) {
+	vcc = atm_sk(s);
+	if (vcc->dev != fore200e->atm_dev)
+		continue;
+	if (vcc->vpi == rpd->atm_header.vpi && vcc->vci == rpd->atm_header.vci) {
+            read_unlock(&vcc_sklist_lock);
+	    return vcc;
+	}
     }
-    spin_unlock_irqrestore(&fore200e->atm_dev->lock, flags);
-    
-    return vcc;
+    read_unlock(&vcc_sklist_lock);
+
+    return NULL;
 }
 
 
@@ -1350,20 +1355,26 @@
 static int
 fore200e_walk_vccs(struct atm_vcc *vcc, short *vpi, int *vci)
 {
-    unsigned long flags;
     struct atm_vcc* walk;
+    struct sock *s;
+    struct hlist_node *node;
 
     /* find a free VPI */
 
-    spin_lock_irqsave(&vcc->dev->lock, flags);
+    read_lock(&vcc_sklist_lock);
 
     if (*vpi == ATM_VPI_ANY) {
 
-	for (*vpi = 0, walk = vcc->dev->vccs; walk; walk = walk->next) {
+	*vpi = 0;
+restart_vpi_search:
+	sk_for_each(s, node, &vcc_sklist) {
+	    walk = atm_sk(s);
+	    if (walk->dev != vcc->dev)
+		continue;
 
 	    if ((walk->vci == *vci) && (walk->vpi == *vpi)) {
 		(*vpi)++;
-		walk = vcc->dev->vccs;
+		goto restart_vpi_search;
 	    }
 	}
     }
@@ -1371,16 +1382,21 @@
     /* find a free VCI */
     if (*vci == ATM_VCI_ANY) {
 	
-	for (*vci = ATM_NOT_RSV_VCI, walk = vcc->dev->vccs; walk; walk = walk->next) {
+	*vci = ATM_NOT_RSV_VCI;
+restart_vci_search:
+	sk_for_each(s, node, &vcc_sklist) {
+	    walk = atm_sk(s);
+	    if (walk->dev != vcc->dev)
+		continue;
 
 	    if ((walk->vpi = *vpi) && (walk->vci == *vci)) {
 		*vci = walk->vci + 1;
-		walk = vcc->dev->vccs;
+		goto restart_vci_search;
 	    }
 	}
     }
 
-    spin_unlock_irqrestore(&vcc->dev->lock, flags);
+    read_unlock(&vcc_sklist_lock);
 
     return 0;
 }
@@ -2642,7 +2658,8 @@
 static int
 fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page)
 {
-    unsigned long flags;
+    struct sock *s;
+    struct hlist_node *node;
     struct fore200e* fore200e  = FORE200E_DEV(dev);
     int              len, left = *pos;
 
@@ -2889,8 +2906,12 @@
 	len = sprintf(page,"\n"    
 		      " VCCs:\n  address\tVPI.VCI:AAL\t(min/max tx PDU size) (min/max rx PDU size)\n");
 	
-	spin_lock_irqsave(&fore200e->atm_dev->lock, flags);
-	for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) {
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+	    vcc = atm_sk(s);
+
+	    if (vcc->dev != fore200e->atm_dev)
+		    continue;
 
 	    fore200e_vcc = FORE200E_VCC(vcc);
 	    
@@ -2904,7 +2925,7 @@
 			   fore200e_vcc->rx_max_pdu
 		);
 	}
-	spin_unlock_irqrestore(&fore200e->atm_dev->lock, flags);
+	read_unlock(&vcc_sklist_lock);
 
 	return len;
     }
diff -Nru a/drivers/atm/he.c b/drivers/atm/he.c
--- a/drivers/atm/he.c	Fri Jun 20 16:53:20 2003
+++ b/drivers/atm/he.c	Fri Jun 20 16:53:20 2003
@@ -79,7 +79,6 @@
 #include <linux/sonet.h>
 
 #define USE_TASKLET
-#define USE_HE_FIND_VCC
 #undef USE_SCATTERGATHER
 #undef USE_CHECKSUM_HW			/* still confused about this */
 #define USE_RBPS
@@ -328,25 +327,25 @@
 		he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 7)
 
 static __inline__ struct atm_vcc*
-he_find_vcc(struct he_dev *he_dev, unsigned cid)
+__find_vcc(struct he_dev *he_dev, unsigned cid)
 {
-	unsigned long flags;
 	struct atm_vcc *vcc;
+	struct hlist_node *node;
+	struct sock *s;
 	short vpi;
 	int vci;
 
 	vpi = cid >> he_dev->vcibits;
 	vci = cid & ((1 << he_dev->vcibits) - 1);
 
-	spin_lock_irqsave(&he_dev->atm_dev->lock, flags);
-	for (vcc = he_dev->atm_dev->vccs; vcc; vcc = vcc->next)
-		if (vcc->vci == vci && vcc->vpi == vpi
-			&& vcc->qos.rxtp.traffic_class != ATM_NONE) {
-				spin_unlock_irqrestore(&he_dev->atm_dev->lock, flags);
+	sk_for_each(s, node, &vcc_sklist) {
+		vcc = atm_sk(s);
+		if (vcc->dev == he_dev->atm_dev &&
+		    vcc->vci == vci && vcc->vpi == vpi &&
+		    vcc->qos.rxtp.traffic_class != ATM_NONE) {
 				return vcc;
-			}
-
-	spin_unlock_irqrestore(&he_dev->atm_dev->lock, flags);
+		}
+	}
 	return NULL;
 }
 
@@ -1566,17 +1565,6 @@
 	reg |= RX_ENABLE;
 	he_writel(he_dev, reg, RC_CONFIG);
 
-#ifndef USE_HE_FIND_VCC
-	he_dev->he_vcc_table = kmalloc(sizeof(struct he_vcc_table) * 
-			(1 << (he_dev->vcibits + he_dev->vpibits)), GFP_KERNEL);
-	if (he_dev->he_vcc_table == NULL) {
-		hprintk("failed to alloc he_vcc_table\n");
-		return -ENOMEM;
-	}
-	memset(he_dev->he_vcc_table, 0, sizeof(struct he_vcc_table) *
-				(1 << (he_dev->vcibits + he_dev->vpibits)));
-#endif
-
 	for (i = 0; i < HE_NUM_CS_STPER; ++i) {
 		he_dev->cs_stper[i].inuse = 0;
 		he_dev->cs_stper[i].pcr = -1;
@@ -1712,11 +1700,6 @@
 							he_dev->tpd_base, he_dev->tpd_base_phys);
 #endif
 
-#ifndef USE_HE_FIND_VCC
-	if (he_dev->he_vcc_table)
-		kfree(he_dev->he_vcc_table);
-#endif
-
 	if (he_dev->pci_dev) {
 		pci_read_config_word(he_dev->pci_dev, PCI_COMMAND, &command);
 		command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
@@ -1798,6 +1781,7 @@
 	int pdus_assembled = 0;
 	int updated = 0;
 
+	read_lock(&vcc_sklist_lock);
 	while (he_dev->rbrq_head != rbrq_tail) {
 		++updated;
 
@@ -1823,13 +1807,10 @@
 		buf_len = RBRQ_BUFLEN(he_dev->rbrq_head) * 4;
 		cid = RBRQ_CID(he_dev->rbrq_head);
 
-#ifdef USE_HE_FIND_VCC
 		if (cid != lastcid)
-			vcc = he_find_vcc(he_dev, cid);
+			vcc = __find_vcc(he_dev, cid);
 		lastcid = cid;
-#else
-		vcc = HE_LOOKUP_VCC(he_dev, cid);
-#endif
+
 		if (vcc == NULL) {
 			hprintk("vcc == NULL  (cid 0x%x)\n", cid);
 			if (!RBRQ_HBUF_ERR(he_dev->rbrq_head))
@@ -1966,6 +1947,7 @@
 					RBRQ_MASK(++he_dev->rbrq_head));
 
 	}
+	read_unlock(&vcc_sklist_lock);
 
 	if (updated) {
 		if (updated > he_dev->rbrq_peak)
@@ -2565,10 +2547,6 @@
 #endif
 
 		spin_unlock_irqrestore(&he_dev->global_lock, flags);
-
-#ifndef USE_HE_FIND_VCC
-		HE_LOOKUP_VCC(he_dev, cid) = vcc;
-#endif
 	}
 
 open_failed:
@@ -2634,9 +2612,6 @@
 		if (timeout == 0)
 			hprintk("close rx timeout cid 0x%x\n", cid);
 
-#ifndef USE_HE_FIND_VCC
-		HE_LOOKUP_VCC(he_dev, cid) = NULL;
-#endif
 		HPRINTK("close rx cid 0x%x complete\n", cid);
 
 	}
diff -Nru a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
--- a/drivers/atm/idt77252.c	Fri Jun 20 16:53:20 2003
+++ b/drivers/atm/idt77252.c	Fri Jun 20 16:53:20 2003
@@ -2403,37 +2403,43 @@
 static int
 idt77252_find_vcc(struct atm_vcc *vcc, short *vpi, int *vci)
 {
-	unsigned long flags;
+	struct sock *s;
 	struct atm_vcc *walk;
 
-	spin_lock_irqsave(&vcc->dev->lock, flags);
+	read_lock(&vcc_sklist_lock);
 	if (*vpi == ATM_VPI_ANY) {
 		*vpi = 0;
-		walk = vcc->dev->vccs;
-		while (walk) {
+		s = sk_head(&vcc_sklist);
+		while (s) {
+			walk = atm_sk(s);
+			if (walk->dev != vcc->dev)
+				continue;
 			if ((walk->vci == *vci) && (walk->vpi == *vpi)) {
 				(*vpi)++;
-				walk = vcc->dev->vccs;
+				s = sk_head(&vcc_sklist);
 				continue;
 			}
-			walk = walk->next;
+			s = sk_next(s);
 		}
 	}
 
 	if (*vci == ATM_VCI_ANY) {
 		*vci = ATM_NOT_RSV_VCI;
-		walk = vcc->dev->vccs;
-		while (walk) {
+		s = sk_head(&vcc_sklist);
+		while (s) {
+			walk = atm_sk(s);
+			if (walk->dev != vcc->dev)
+				continue;
 			if ((walk->vci == *vci) && (walk->vpi == *vpi)) {
 				(*vci)++;
-				walk = vcc->dev->vccs;
+				s = sk_head(&vcc_sklist);
 				continue;
 			}
-			walk = walk->next;
+			s = sk_next(s);
 		}
 	}
 
-	spin_unlock_irqrestore(&vcc->dev->lock, flags);
+	read_unlock(&vcc_sklist_lock);
 	return 0;
 }
 
diff -Nru a/net/atm/atm_misc.c b/net/atm/atm_misc.c
--- a/net/atm/atm_misc.c	Fri Jun 20 16:53:20 2003
+++ b/net/atm/atm_misc.c	Fri Jun 20 16:53:20 2003
@@ -47,15 +47,21 @@
 
 static int check_ci(struct atm_vcc *vcc,short vpi,int vci)
 {
+	struct hlist_node *node;
+	struct sock *s;
 	struct atm_vcc *walk;
 
-	for (walk = vcc->dev->vccs; walk; walk = walk->next)
+	sk_for_each(s, node, &vcc_sklist) {
+		walk = atm_sk(s);
+		if (walk->dev != vcc->dev)
+			continue;
 		if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vpi == vpi &&
 		    walk->vci == vci && ((walk->qos.txtp.traffic_class !=
 		    ATM_NONE && vcc->qos.txtp.traffic_class != ATM_NONE) ||
 		    (walk->qos.rxtp.traffic_class != ATM_NONE &&
 		    vcc->qos.rxtp.traffic_class != ATM_NONE)))
 			return -EADDRINUSE;
+	}
 		/* allow VCCs with same VPI/VCI iff they don't collide on
 		   TX/RX (but we may refuse such sharing for other reasons,
 		   e.g. if protocol requires to have both channels) */
@@ -65,17 +71,16 @@
 
 int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci)
 {
-	unsigned long flags;
 	static short p = 0; /* poor man's per-device cache */
 	static int c = 0;
 	short old_p;
 	int old_c;
 	int err;
 
-	spin_lock_irqsave(&vcc->dev->lock, flags);
+	read_lock(&vcc_sklist_lock);
 	if (*vpi != ATM_VPI_ANY && *vci != ATM_VCI_ANY) {
 		err = check_ci(vcc,*vpi,*vci);
-		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		read_unlock(&vcc_sklist_lock);
 		return err;
 	}
 	/* last scan may have left values out of bounds for current device */
@@ -90,7 +95,7 @@
 		if (!check_ci(vcc,p,c)) {
 			*vpi = p;
 			*vci = c;
-			spin_unlock_irqrestore(&vcc->dev->lock, flags);
+			read_unlock(&vcc_sklist_lock);
 			return 0;
 		}
 		if (*vci == ATM_VCI_ANY) {
@@ -105,7 +110,7 @@
 		}
 	}
 	while (old_p != p || old_c != c);
-	spin_unlock_irqrestore(&vcc->dev->lock, flags);
+	read_unlock(&vcc_sklist_lock);
 	return -EADDRINUSE;
 }
 
diff -Nru a/net/atm/clip.c b/net/atm/clip.c
--- a/net/atm/clip.c	Fri Jun 20 16:53:20 2003
+++ b/net/atm/clip.c	Fri Jun 20 16:53:20 2003
@@ -737,7 +737,8 @@
 	set_bit(ATM_VF_META,&vcc->flags);
 	set_bit(ATM_VF_READY,&vcc->flags);
 	    /* allow replies and avoid getting closed if signaling dies */
-	bind_vcc(vcc,&atmarpd_dev);
+	vcc->dev = &atmarpd_dev;
+	vcc_insert_socket(vcc->sk);
 	vcc->push = NULL;
 	vcc->pop = NULL; /* crash */
 	vcc->push_oam = NULL; /* crash */
diff -Nru a/net/atm/common.c b/net/atm/common.c
--- a/net/atm/common.c	Fri Jun 20 16:53:20 2003
+++ b/net/atm/common.c	Fri Jun 20 16:53:20 2003
@@ -157,6 +157,29 @@
 #endif
 
 
+HLIST_HEAD(vcc_sklist);
+rwlock_t vcc_sklist_lock = RW_LOCK_UNLOCKED;
+
+void __vcc_insert_socket(struct sock *sk)
+{
+	sk_add_node(sk, &vcc_sklist);
+}
+
+void vcc_insert_socket(struct sock *sk)
+{
+	write_lock_irq(&vcc_sklist_lock);
+	__vcc_insert_socket(sk);
+	write_unlock_irq(&vcc_sklist_lock);
+}
+
+void vcc_remove_socket(struct sock *sk)
+{
+	write_lock_irq(&vcc_sklist_lock);
+	sk_del_node_init(sk);
+	write_unlock_irq(&vcc_sklist_lock);
+}
+
+
 static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
 {
 	struct sk_buff *skb;
@@ -175,16 +198,45 @@
 }
 
 
-int atm_create(struct socket *sock,int protocol,int family)
+EXPORT_SYMBOL(vcc_sklist);
+EXPORT_SYMBOL(vcc_sklist_lock);
+EXPORT_SYMBOL(vcc_insert_socket);
+EXPORT_SYMBOL(vcc_remove_socket);
+
+static void vcc_sock_destruct(struct sock *sk)
+{
+	struct atm_vcc *vcc = atm_sk(sk);
+
+	if (atomic_read(&vcc->sk->sk_rmem_alloc))
+		printk(KERN_DEBUG "vcc_sock_destruct: rmem leakage (%d bytes) detected.\n", atomic_read(&sk->sk_rmem_alloc));
+
+	if (atomic_read(&vcc->sk->sk_wmem_alloc))
+		printk(KERN_DEBUG "vcc_sock_destruct: wmem leakage (%d bytes) detected.\n", atomic_read(&sk->sk_wmem_alloc));
+
+	kfree(sk->sk_protinfo);
+}
+ 
+int vcc_create(struct socket *sock, int protocol, int family)
 {
 	struct sock *sk;
 	struct atm_vcc *vcc;
 
 	sock->sk = NULL;
-	if (sock->type == SOCK_STREAM) return -EINVAL;
-	if (!(sk = alloc_atm_vcc_sk(family))) return -ENOMEM;
-	vcc = atm_sk(sk);
-	memset(&vcc->flags,0,sizeof(vcc->flags));
+	if (sock->type == SOCK_STREAM)
+		return -EINVAL;
+	sk = sk_alloc(family, GFP_KERNEL, 1, NULL);
+	if (!sk)
+		return -ENOMEM;
+	sock_init_data(NULL, sk);
+
+	vcc = atm_sk(sk) = kmalloc(sizeof(*vcc), GFP_KERNEL);
+	if (!vcc) {
+		sk_free(sk);
+		return -ENOMEM;
+	}
+
+	memset(vcc, 0, sizeof(*vcc));
+	vcc->sk = sk;
 	vcc->dev = NULL;
 	vcc->callback = NULL;
 	memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc));
@@ -199,42 +251,48 @@
 	vcc->atm_options = vcc->aal_options = 0;
 	init_waitqueue_head(&vcc->sleep);
 	sk->sk_sleep = &vcc->sleep;
+	sk->sk_destruct = vcc_sock_destruct;
 	sock->sk = sk;
 	return 0;
 }
 
 
-void atm_release_vcc_sk(struct sock *sk,int free_sk)
+static void vcc_destroy_socket(struct sock *sk)
 {
 	struct atm_vcc *vcc = atm_sk(sk);
 	struct sk_buff *skb;
 
-	clear_bit(ATM_VF_READY,&vcc->flags);
+	clear_bit(ATM_VF_READY, &vcc->flags);
 	if (vcc->dev) {
-		if (vcc->dev->ops->close) vcc->dev->ops->close(vcc);
-		if (vcc->push) vcc->push(vcc,NULL); /* atmarpd has no push */
+		if (vcc->dev->ops->close)
+			vcc->dev->ops->close(vcc);
+		if (vcc->push)
+			vcc->push(vcc, NULL); /* atmarpd has no push */
+
+		vcc_remove_socket(sk);	/* no more receive */
+
 		while ((skb = skb_dequeue(&vcc->sk->sk_receive_queue))) {
 			atm_return(vcc,skb->truesize);
 			kfree_skb(skb);
 		}
 
 		module_put(vcc->dev->ops->owner);
-		atm_dev_release(vcc->dev);
-		if (atomic_read(&vcc->sk->sk_rmem_alloc))
-			printk(KERN_WARNING "atm_release_vcc: strange ... "
-			    "rmem_alloc == %d after closing\n",
-			    atomic_read(&vcc->sk->sk_rmem_alloc));
-		bind_vcc(vcc,NULL);
+		atm_dev_put(vcc->dev);
 	}
-
-	if (free_sk) free_atm_vcc_sk(sk);
 }
 
 
-int atm_release(struct socket *sock)
+int vcc_release(struct socket *sock)
 {
-	if (sock->sk)
-		atm_release_vcc_sk(sock->sk,1);
+	struct sock *sk = sock->sk;
+
+	if (sk) {
+		lock_sock(sk);
+		vcc_destroy_socket(sock->sk);
+		release_sock(sk);
+		sock_put(sk);
+	}
+
 	return 0;
 }
 
@@ -289,7 +347,8 @@
 	if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE))
 		return -EPERM;
 	error = 0;
-	bind_vcc(vcc,dev);
+	vcc->dev = dev;
+	vcc_insert_socket(vcc->sk);
 	switch (vcc->qos.aal) {
 		case ATM_AAL0:
 			error = atm_init_aal0(vcc);
@@ -313,7 +372,7 @@
 	if (!error) error = adjust_tp(&vcc->qos.txtp,vcc->qos.aal);
 	if (!error) error = adjust_tp(&vcc->qos.rxtp,vcc->qos.aal);
 	if (error) {
-		bind_vcc(vcc,NULL);
+		vcc_remove_socket(vcc->sk);
 		return error;
 	}
 	DPRINTK("VCC %d.%d, AAL %d\n",vpi,vci,vcc->qos.aal);
@@ -327,7 +386,7 @@
 		error = dev->ops->open(vcc,vpi,vci);
 		if (error) {
 			module_put(dev->ops->owner);
-			bind_vcc(vcc,NULL);
+			vcc_remove_socket(vcc->sk);
 			return error;
 		}
 	}
@@ -371,7 +430,7 @@
 		dev = atm_dev_lookup(itf);
 		error = __vcc_connect(vcc, dev, vpi, vci);
 		if (error) {
-			atm_dev_release(dev);
+			atm_dev_put(dev);
 			return error;
 		}
 	} else {
@@ -385,7 +444,7 @@
 			spin_unlock(&atm_dev_lock);
 			if (!__vcc_connect(vcc, dev, vpi, vci))
 				break;
-			atm_dev_release(dev);
+			atm_dev_put(dev);
 			dev = NULL;
 			spin_lock(&atm_dev_lock);
 		}
diff -Nru a/net/atm/common.h b/net/atm/common.h
--- a/net/atm/common.h	Fri Jun 20 16:53:20 2003
+++ b/net/atm/common.h	Fri Jun 20 16:53:20 2003
@@ -10,8 +10,8 @@
 #include <linux/poll.h> /* for poll_table */
 
 
-int atm_create(struct socket *sock,int protocol,int family);
-int atm_release(struct socket *sock);
+int vcc_create(struct socket *sock, int protocol, int family);
+int vcc_release(struct socket *sock);
 int vcc_connect(struct socket *sock, int itf, short vpi, int vci);
 int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
 		int size, int flags);
@@ -24,7 +24,6 @@
 int vcc_getsockopt(struct socket *sock, int level, int optname, char *optval,
 		   int *optlen);
 
-void atm_release_vcc_sk(struct sock *sk,int free_sk);
 void atm_shutdown_dev(struct atm_dev *dev);
 
 int atmpvc_init(void);
diff -Nru a/net/atm/lec.c b/net/atm/lec.c
--- a/net/atm/lec.c	Fri Jun 20 16:53:20 2003
+++ b/net/atm/lec.c	Fri Jun 20 16:53:20 2003
@@ -48,7 +48,7 @@
 
 #include "lec.h"
 #include "lec_arpc.h"
-#include "resources.h"  /* for bind_vcc() */
+#include "resources.h"
 
 #if 0
 #define DPRINTK printk
@@ -810,7 +810,8 @@
         lec_arp_init(priv);
 	priv->itfnum = i;  /* LANE2 addition */
         priv->lecd = vcc;
-        bind_vcc(vcc, &lecatm_dev);
+        vcc->dev = &lecatm_dev;
+        vcc_insert_socket(vcc->sk);
         
         vcc->proto_data = dev_lec[i];
 	set_bit(ATM_VF_META,&vcc->flags);
diff -Nru a/net/atm/mpc.c b/net/atm/mpc.c
--- a/net/atm/mpc.c	Fri Jun 20 16:53:20 2003
+++ b/net/atm/mpc.c	Fri Jun 20 16:53:20 2003
@@ -28,7 +28,7 @@
 
 #include "lec.h"
 #include "mpc.h"
-#include "resources.h"  /* for bind_vcc() */
+#include "resources.h"
 
 /*
  * mpc.c: Implementation of MPOA client kernel part 
@@ -789,7 +789,8 @@
 	}
 
 	mpc->mpoad_vcc = vcc;
-	bind_vcc(vcc, &mpc_dev);
+	vcc->dev = &mpc_dev;
+	vcc_insert_socket(vcc->sk);
 	set_bit(ATM_VF_META,&vcc->flags);
 	set_bit(ATM_VF_READY,&vcc->flags);
 
diff -Nru a/net/atm/proc.c b/net/atm/proc.c
--- a/net/atm/proc.c	Fri Jun 20 16:53:20 2003
+++ b/net/atm/proc.c	Fri Jun 20 16:53:20 2003
@@ -334,9 +334,8 @@
 
 static int atm_pvc_info(loff_t pos,char *buf)
 {
-	unsigned long flags;
-	struct atm_dev *dev;
-	struct list_head *p;
+	struct hlist_node *node;
+	struct sock *s;
 	struct atm_vcc *vcc;
 	int left, clip_info = 0;
 
@@ -349,25 +348,20 @@
 	if (try_atm_clip_ops())
 		clip_info = 1;
 #endif
-	spin_lock(&atm_dev_lock);
-	list_for_each(p, &atm_devs) {
-		dev = list_entry(p, struct atm_dev, dev_list);
-		spin_lock_irqsave(&dev->lock, flags);
-		for (vcc = dev->vccs; vcc; vcc = vcc->next)
-			if (vcc->sk->sk_family == PF_ATMPVC &&
-			    vcc->dev && !left--) {
-				pvc_info(vcc,buf,clip_info);
-				spin_unlock_irqrestore(&dev->lock, flags);
-				spin_unlock(&atm_dev_lock);
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+		vcc = atm_sk(s);
+		if (vcc->sk->sk_family == PF_ATMPVC && vcc->dev && !left--) {
+			pvc_info(vcc,buf,clip_info);
+			read_unlock(&vcc_sklist_lock);
 #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
-				if (clip_info)
-					module_put(atm_clip_ops->owner);
+			if (clip_info)
+				module_put(atm_clip_ops->owner);
 #endif
-				return strlen(buf);
-			}
-		spin_unlock_irqrestore(&dev->lock, flags);
+			return strlen(buf);
+		}
 	}
-	spin_unlock(&atm_dev_lock);
+	read_unlock(&vcc_sklist_lock);
 #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
 	if (clip_info)
 		module_put(atm_clip_ops->owner);
@@ -378,10 +372,9 @@
 
 static int atm_vc_info(loff_t pos,char *buf)
 {
-	unsigned long flags;
-	struct atm_dev *dev;
-	struct list_head *p;
 	struct atm_vcc *vcc;
+	struct hlist_node *node;
+	struct sock *s;
 	int left;
 
 	if (!pos)
@@ -389,20 +382,16 @@
 		    "Address"," Itf VPI VCI   Fam Flags Reply Send buffer"
 		    "     Recv buffer\n");
 	left = pos-1;
-	spin_lock(&atm_dev_lock);
-	list_for_each(p, &atm_devs) {
-		dev = list_entry(p, struct atm_dev, dev_list);
-		spin_lock_irqsave(&dev->lock, flags);
-		for (vcc = dev->vccs; vcc; vcc = vcc->next)
-			if (!left--) {
-				vc_info(vcc,buf);
-				spin_unlock_irqrestore(&dev->lock, flags);
-				spin_unlock(&atm_dev_lock);
-				return strlen(buf);
-			}
-		spin_unlock_irqrestore(&dev->lock, flags);
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+		vcc = atm_sk(s);
+		if (!left--) {
+			vc_info(vcc,buf);
+			read_unlock(&vcc_sklist_lock);
+			return strlen(buf);
+		}
 	}
-	spin_unlock(&atm_dev_lock);
+	read_unlock(&vcc_sklist_lock);
 
 	return 0;
 }
@@ -410,29 +399,24 @@
 
 static int atm_svc_info(loff_t pos,char *buf)
 {
-	unsigned long flags;
-	struct atm_dev *dev;
-	struct list_head *p;
+	struct hlist_node *node;
+	struct sock *s;
 	struct atm_vcc *vcc;
 	int left;
 
 	if (!pos)
 		return sprintf(buf,"Itf VPI VCI           State      Remote\n");
 	left = pos-1;
-	spin_lock(&atm_dev_lock);
-	list_for_each(p, &atm_devs) {
-		dev = list_entry(p, struct atm_dev, dev_list);
-		spin_lock_irqsave(&dev->lock, flags);
-		for (vcc = dev->vccs; vcc; vcc = vcc->next)
-			if (vcc->sk->sk_family == PF_ATMSVC && !left--) {
-				svc_info(vcc,buf);
-				spin_unlock_irqrestore(&dev->lock, flags);
-				spin_unlock(&atm_dev_lock);
-				return strlen(buf);
-			}
-		spin_unlock_irqrestore(&dev->lock, flags);
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+		vcc = atm_sk(s);
+		if (vcc->sk->sk_family == PF_ATMSVC && !left--) {
+			svc_info(vcc,buf);
+			read_unlock(&vcc_sklist_lock);
+			return strlen(buf);
+		}
 	}
-	spin_unlock(&atm_dev_lock);
+	read_unlock(&vcc_sklist_lock);
 
 	return 0;
 }
diff -Nru a/net/atm/pvc.c b/net/atm/pvc.c
--- a/net/atm/pvc.c	Fri Jun 20 16:53:20 2003
+++ b/net/atm/pvc.c	Fri Jun 20 16:53:20 2003
@@ -17,10 +17,6 @@
 #include "resources.h"		/* devs and vccs */
 #include "common.h"		/* common for PVCs and SVCs */
 
-#ifndef NULL
-#define NULL 0
-#endif
-
 
 static int pvc_shutdown(struct socket *sock,int how)
 {
@@ -109,7 +105,7 @@
 static struct proto_ops pvc_proto_ops = {
 	.family =	PF_ATMPVC,
 
-	.release =	atm_release,
+	.release =	vcc_release,
 	.bind =		pvc_bind,
 	.connect =	pvc_connect,
 	.socketpair =	sock_no_socketpair,
@@ -131,7 +127,7 @@
 static int pvc_create(struct socket *sock,int protocol)
 {
 	sock->ops = &pvc_proto_ops;
-	return atm_create(sock,protocol,PF_ATMPVC);
+	return vcc_create(sock, protocol, PF_ATMPVC);
 }
 
 
diff -Nru a/net/atm/resources.c b/net/atm/resources.c
--- a/net/atm/resources.c	Fri Jun 20 16:53:20 2003
+++ b/net/atm/resources.c	Fri Jun 20 16:53:20 2003
@@ -23,11 +23,6 @@
 #include "addr.h"
 
 
-#ifndef NULL
-#define NULL 0
-#endif
-
-
 LIST_HEAD(atm_devs);
 spinlock_t atm_dev_lock = SPIN_LOCK_UNLOCKED;
 
@@ -91,7 +86,7 @@
 	spin_lock(&atm_dev_lock);
 	if (number != -1) {
 		if ((inuse = __atm_dev_lookup(number))) {
-			atm_dev_release(inuse);
+			atm_dev_put(inuse);
 			spin_unlock(&atm_dev_lock);
 			__free_atm_dev(dev);
 			return NULL;
@@ -100,7 +95,7 @@
 	} else {
 		dev->number = 0;
 		while ((inuse = __atm_dev_lookup(dev->number))) {
-			atm_dev_release(inuse);
+			atm_dev_put(inuse);
 			dev->number++;
 		}
 	}
@@ -402,78 +397,12 @@
 	else
 		error = 0;
 done:
-	atm_dev_release(dev);
+	atm_dev_put(dev);
 	return error;
 }
 
 
-struct sock *alloc_atm_vcc_sk(int family)
-{
-	struct sock *sk;
-	struct atm_vcc *vcc;
-
-	sk = sk_alloc(family, GFP_KERNEL, 1, NULL);
-	if (!sk)
-		return NULL;
-	vcc = atm_sk(sk) = kmalloc(sizeof(*vcc), GFP_KERNEL);
-	if (!vcc) {
-		sk_free(sk);
-		return NULL;
-	}
-	sock_init_data(NULL, sk);
-	memset(vcc, 0, sizeof(*vcc));
-	vcc->sk = sk;
-
-	return sk;
-}
-
-
-static void unlink_vcc(struct atm_vcc *vcc)
-{
-	unsigned long flags;
-	if (vcc->dev) {
-		spin_lock_irqsave(&vcc->dev->lock, flags);
-		if (vcc->prev)
-			vcc->prev->next = vcc->next;
-		else
-			vcc->dev->vccs = vcc->next;
-
-		if (vcc->next)
-			vcc->next->prev = vcc->prev;
-		else
-			vcc->dev->last = vcc->prev;
-		spin_unlock_irqrestore(&vcc->dev->lock, flags);
-	}
-}
-
-
-void free_atm_vcc_sk(struct sock *sk)
-{
-	unlink_vcc(atm_sk(sk));
-	sk_free(sk);
-}
-
-void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev)
-{
-	unsigned long flags;
-
-	unlink_vcc(vcc);
-	vcc->dev = dev;
-	if (dev) {
-		spin_lock_irqsave(&dev->lock, flags);
-		vcc->next = NULL;
-		vcc->prev = dev->last;
-		if (dev->vccs)
-			dev->last->next = vcc;
-		else
-			dev->vccs = vcc;
-		dev->last = vcc;
-		spin_unlock_irqrestore(&dev->lock, flags);
-	}
-}
-
 EXPORT_SYMBOL(atm_dev_register);
 EXPORT_SYMBOL(atm_dev_deregister);
 EXPORT_SYMBOL(atm_dev_lookup);
 EXPORT_SYMBOL(shutdown_atm_dev);
-EXPORT_SYMBOL(bind_vcc);
diff -Nru a/net/atm/resources.h b/net/atm/resources.h
--- a/net/atm/resources.h	Fri Jun 20 16:53:20 2003
+++ b/net/atm/resources.h	Fri Jun 20 16:53:20 2003
@@ -14,8 +14,6 @@
 extern spinlock_t atm_dev_lock;
 
 
-struct sock *alloc_atm_vcc_sk(int family);
-void free_atm_vcc_sk(struct sock *sk);
 int atm_dev_ioctl(unsigned int cmd, unsigned long arg);
 
 
diff -Nru a/net/atm/signaling.c b/net/atm/signaling.c
--- a/net/atm/signaling.c	Fri Jun 20 16:53:20 2003
+++ b/net/atm/signaling.c	Fri Jun 20 16:53:20 2003
@@ -200,26 +200,22 @@
 }
 
 
-static void purge_vccs(struct atm_vcc *vcc)
+static void purge_vcc(struct atm_vcc *vcc)
 {
-	while (vcc) {
-		if (vcc->sk->sk_family == PF_ATMSVC &&
-		    !test_bit(ATM_VF_META,&vcc->flags)) {
-			set_bit(ATM_VF_RELEASED,&vcc->flags);
-			vcc->reply = -EUNATCH;
-			vcc->sk->sk_err = EUNATCH;
-			wake_up(&vcc->sleep);
-		}
-		vcc = vcc->next;
+	if (vcc->sk->sk_family == PF_ATMSVC &&
+	    !test_bit(ATM_VF_META,&vcc->flags)) {
+		set_bit(ATM_VF_RELEASED,&vcc->flags);
+		vcc->reply = -EUNATCH;
+		vcc->sk->sk_err = EUNATCH;
+		wake_up(&vcc->sleep);
 	}
 }
 
 
 static void sigd_close(struct atm_vcc *vcc)
 {
-	unsigned long flags;
-	struct atm_dev *dev;
-	struct list_head *p;
+	struct hlist_node *node;
+	struct sock *s;
 
 	DPRINTK("sigd_close\n");
 	sigd = NULL;
@@ -227,14 +223,14 @@
 		printk(KERN_ERR "sigd_close: closing with requests pending\n");
 	skb_queue_purge(&vcc->sk->sk_receive_queue);
 
-	spin_lock(&atm_dev_lock);
-	list_for_each(p, &atm_devs) {
-		dev = list_entry(p, struct atm_dev, dev_list);
-		spin_lock_irqsave(&dev->lock, flags);
-		purge_vccs(dev->vccs);
-		spin_unlock_irqrestore(&dev->lock, flags);
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+		struct atm_vcc *vcc = atm_sk(s);
+
+		if (vcc->dev)
+			purge_vcc(vcc);
 	}
-	spin_unlock(&atm_dev_lock);
+	read_unlock(&vcc_sklist_lock);
 }
 
 
@@ -257,7 +253,8 @@
 	if (sigd) return -EADDRINUSE;
 	DPRINTK("sigd_attach\n");
 	sigd = vcc;
-	bind_vcc(vcc,&sigd_dev);
+	vcc->dev = &sigd_dev;
+	vcc_insert_socket(vcc->sk);
 	set_bit(ATM_VF_META,&vcc->flags);
 	set_bit(ATM_VF_READY,&vcc->flags);
 	wake_up(&sigd_sleep);
diff -Nru a/net/atm/svc.c b/net/atm/svc.c
--- a/net/atm/svc.c	Fri Jun 20 16:53:20 2003
+++ b/net/atm/svc.c	Fri Jun 20 16:53:20 2003
@@ -88,18 +88,21 @@
 
 static int svc_release(struct socket *sock)
 {
+	struct sock *sk = sock->sk;
 	struct atm_vcc *vcc;
 
-	if (!sock->sk) return 0;
-	vcc = ATM_SD(sock);
-	DPRINTK("svc_release %p\n",vcc);
-	clear_bit(ATM_VF_READY,&vcc->flags);
-	atm_release_vcc_sk(sock->sk,0);
-	svc_disconnect(vcc);
-	    /* VCC pointer is used as a reference, so we must not free it
-	       (thereby subjecting it to re-use) before all pending connections
-	        are closed */
-	free_atm_vcc_sk(sock->sk);
+	if (sk)  {
+		vcc = ATM_SD(sock);
+		DPRINTK("svc_release %p\n", vcc);
+		clear_bit(ATM_VF_READY, &vcc->flags);
+		/* VCC pointer is used as a reference, so we must not free it
+		   (thereby subjecting it to re-use) before all pending connections
+	           are closed */
+		sock_hold(sk);
+		vcc_release(sock);
+		svc_disconnect(vcc);
+		sock_put(sk);
+	}
 	return 0;
 }
 
@@ -542,7 +545,7 @@
 	int error;
 
 	sock->ops = &svc_proto_ops;
-	error = atm_create(sock,protocol,AF_ATMSVC);
+	error = vcc_create(sock, protocol, AF_ATMSVC);
 	if (error) return error;
 	ATM_SD(sock)->callback = svc_callback;
 	ATM_SD(sock)->local.sas_family = AF_ATMSVC;

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

* Re: [PATCH][ATM][3/3] assorted changes for atm
  2003-06-20 20:53   ` chas williams
@ 2003-06-20 21:32     ` chas williams
  0 siblings, 0 replies; 5+ messages in thread
From: chas williams @ 2003-06-20 21:32 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev

ok, one more time.  maybe i could post the complete patch this time.

[atm]: move vcc's to global sk-based linked list

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.1359  -> 1.1360 
#	    drivers/atm/he.c	1.15    -> 1.16   
#	  net/atm/atm_misc.c	1.7     -> 1.8    
#	   drivers/atm/eni.c	1.17    -> 1.18   
#	      net/atm/proc.c	1.20    -> 1.21   
#	       net/atm/pvc.c	1.16    -> 1.17   
#	drivers/atm/idt77252.c	1.17    -> 1.18   
#	       net/atm/lec.c	1.29    -> 1.30   
#	drivers/atm/atmtcp.c	1.10    -> 1.11   
#	       net/atm/svc.c	1.18    -> 1.19   
#	    net/atm/common.h	1.12    -> 1.13   
#	 net/atm/signaling.c	1.14    -> 1.15   
#	 net/atm/resources.h	1.7     -> 1.8    
#	       net/atm/mpc.c	1.20    -> 1.21   
#	include/linux/atmdev.h	1.18    -> 1.19   
#	 net/atm/resources.c	1.13    -> 1.14   
#	      net/atm/clip.c	1.17    -> 1.18   
#	drivers/atm/fore200e.c	1.18    -> 1.19   
#	    net/atm/common.c	1.35    -> 1.36   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/06/20	chas@relax.cmf.nrl.navy.mil	1.1360
# move vcc's to global sk-based linked list
# --------------------------------------------
#
diff -Nru a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c
--- a/drivers/atm/atmtcp.c	Fri Jun 20 17:33:36 2003
+++ b/drivers/atm/atmtcp.c	Fri Jun 20 17:33:36 2003
@@ -153,9 +153,10 @@
 
 static int atmtcp_v_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
 {
-	unsigned long flags;
 	struct atm_cirange ci;
 	struct atm_vcc *vcc;
+	struct hlist_node *node;
+	struct sock *s;
 
 	if (cmd != ATM_SETCIRANGE) return -ENOIOCTLCMD;
 	if (copy_from_user(&ci,(void *) arg,sizeof(ci))) return -EFAULT;
@@ -163,14 +164,18 @@
 	if (ci.vci_bits == ATM_CI_MAX) ci.vci_bits = MAX_VCI_BITS;
 	if (ci.vpi_bits > MAX_VPI_BITS || ci.vpi_bits < 0 ||
 	    ci.vci_bits > MAX_VCI_BITS || ci.vci_bits < 0) return -EINVAL;
-	spin_lock_irqsave(&dev->lock, flags);
-	for (vcc = dev->vccs; vcc; vcc = vcc->next)
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+		vcc = atm_sk(s);
+		if (vcc->dev != dev)
+			continue;
 		if ((vcc->vpi >> ci.vpi_bits) ||
 		    (vcc->vci >> ci.vci_bits)) {
-			spin_unlock_irqrestore(&dev->lock, flags);
+			read_unlock(&vcc_sklist_lock);
 			return -EBUSY;
 		}
-	spin_unlock_irqrestore(&dev->lock, flags);
+	}
+	read_unlock(&vcc_sklist_lock);
 	dev->ci_range = ci;
 	return 0;
 }
@@ -233,9 +238,10 @@
 
 static void atmtcp_c_close(struct atm_vcc *vcc)
 {
-	unsigned long flags;
 	struct atm_dev *atmtcp_dev;
 	struct atmtcp_dev_data *dev_data;
+	struct sock *s;
+	struct hlist_node *node;
 	struct atm_vcc *walk;
 
 	atmtcp_dev = (struct atm_dev *) vcc->dev_data;
@@ -246,19 +252,24 @@
 	kfree(dev_data);
 	shutdown_atm_dev(atmtcp_dev);
 	vcc->dev_data = NULL;
-	spin_lock_irqsave(&atmtcp_dev->lock, flags);
-	for (walk = atmtcp_dev->vccs; walk; walk = walk->next)
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+		walk = atm_sk(s);
+		if (walk->dev != atmtcp_dev)
+			continue;
 		wake_up(&walk->sleep);
-	spin_unlock_irqrestore(&atmtcp_dev->lock, flags);
+	}
+	read_unlock(&vcc_sklist_lock);
 }
 
 
 static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb)
 {
-	unsigned long flags;
 	struct atm_dev *dev;
 	struct atmtcp_hdr *hdr;
-	struct atm_vcc *out_vcc;
+	struct sock *s;
+	struct hlist_node *node;
+	struct atm_vcc *out_vcc = NULL;
 	struct sk_buff *new_skb;
 	int result = 0;
 
@@ -270,13 +281,17 @@
 		    (struct atmtcp_control *) skb->data);
 		goto done;
 	}
-	spin_lock_irqsave(&dev->lock, flags);
-	for (out_vcc = dev->vccs; out_vcc; out_vcc = out_vcc->next)
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+		out_vcc = atm_sk(s);
+		if (out_vcc->dev != dev)
+			continue;
 		if (out_vcc->vpi == ntohs(hdr->vpi) &&
 		    out_vcc->vci == ntohs(hdr->vci) &&
 		    out_vcc->qos.rxtp.traffic_class != ATM_NONE)
 			break;
-	spin_unlock_irqrestore(&dev->lock, flags);
+	}
+	read_unlock(&vcc_sklist_lock);
 	if (!out_vcc) {
 		atomic_inc(&vcc->stats->tx_err);
 		goto done;
@@ -366,7 +381,7 @@
 	if (itf != -1) dev = atm_dev_lookup(itf);
 	if (dev) {
 		if (dev->ops != &atmtcp_v_dev_ops) {
-			atm_dev_release(dev);
+			atm_dev_put(dev);
 			return -EMEDIUMTYPE;
 		}
 		if (PRIV(dev)->vcc) return -EBUSY;
@@ -378,7 +393,8 @@
 		if (error) return error;
 	}
 	PRIV(dev)->vcc = vcc;
-	bind_vcc(vcc,&atmtcp_control_dev);
+	vcc->dev = &atmtcp_control_dev;
+	vcc_insert_socket(vcc->sk);
 	set_bit(ATM_VF_META,&vcc->flags);
 	set_bit(ATM_VF_READY,&vcc->flags);
 	vcc->dev_data = dev;
@@ -402,7 +418,7 @@
 	dev = atm_dev_lookup(itf);
 	if (!dev) return -ENODEV;
 	if (dev->ops != &atmtcp_v_dev_ops) {
-		atm_dev_release(dev);
+		atm_dev_put(dev);
 		return -EMEDIUMTYPE;
 	}
 	dev_data = PRIV(dev);
@@ -410,7 +426,7 @@
 	dev_data->persist = 0;
 	if (PRIV(dev)->vcc) return 0;
 	kfree(dev_data);
-	atm_dev_release(dev);
+	atm_dev_put(dev);
 	shutdown_atm_dev(dev);
 	return 0;
 }
diff -Nru a/drivers/atm/eni.c b/drivers/atm/eni.c
--- a/drivers/atm/eni.c	Fri Jun 20 17:33:36 2003
+++ b/drivers/atm/eni.c	Fri Jun 20 17:33:36 2003
@@ -1887,10 +1887,11 @@
 
 static int get_ci(struct atm_vcc *vcc,short *vpi,int *vci)
 {
-	unsigned long flags;
+	struct sock *s;
+	struct hlist_node *node;
 	struct atm_vcc *walk;
 
-	spin_lock_irqsave(&vcc->dev->lock, flags);
+	read_lock(&vcc_sklist_lock);
 	if (*vpi == ATM_VPI_ANY) *vpi = 0;
 	if (*vci == ATM_VCI_ANY) {
 		for (*vci = ATM_NOT_RSV_VCI; *vci < NR_VCI; (*vci)++) {
@@ -1898,40 +1899,48 @@
 			    ENI_DEV(vcc->dev)->rx_map[*vci])
 				continue;
 			if (vcc->qos.txtp.traffic_class != ATM_NONE) {
-				for (walk = vcc->dev->vccs; walk;
-				    walk = walk->next)
+				sk_for_each(s, node, &vcc_sklist) {
+					walk = atm_sk(s);
+					if (walk->dev != vcc->dev)
+						continue;
 					if (test_bit(ATM_VF_ADDR,&walk->flags)
 					    && walk->vci == *vci &&
 					    walk->qos.txtp.traffic_class !=
 					    ATM_NONE)
 						break;
-				if (walk) continue;
+				}
+				if (node)
+					continue;
 			}
 			break;
 		}
-		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		read_unlock(&vcc_sklist_lock);
 		return *vci == NR_VCI ? -EADDRINUSE : 0;
 	}
 	if (*vci == ATM_VCI_UNSPEC) {
-		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		read_unlock(&vcc_sklist_lock);
 		return 0;
 	}
 	if (vcc->qos.rxtp.traffic_class != ATM_NONE &&
 	    ENI_DEV(vcc->dev)->rx_map[*vci]) {
-		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		read_unlock(&vcc_sklist_lock);
 		return -EADDRINUSE;
 	}
 	if (vcc->qos.txtp.traffic_class == ATM_NONE) {
-		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		read_unlock(&vcc_sklist_lock);
 		return 0;
 	}
-	for (walk = vcc->dev->vccs; walk; walk = walk->next)
+	sk_for_each(s, node, &vcc_sklist) {
+		walk = atm_sk(s);
+		if (walk->dev != vcc->dev)
+			continue;
 		if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vci == *vci &&
 		    walk->qos.txtp.traffic_class != ATM_NONE) {
-			spin_unlock_irqrestore(&vcc->dev->lock, flags);
+			read_unlock(&vcc_sklist_lock);
 			return -EADDRINUSE;
 		}
-	spin_unlock_irqrestore(&vcc->dev->lock, flags);
+	}
+	read_unlock(&vcc_sklist_lock);
 	return 0;
 }
 
@@ -2139,7 +2148,8 @@
 
 static int eni_proc_read(struct atm_dev *dev,loff_t *pos,char *page)
 {
-	unsigned long flags;
+	struct hlist_node *node;
+	struct sock *s;
 	static const char *signal[] = { "LOST","unknown","okay" };
 	struct eni_dev *eni_dev = ENI_DEV(dev);
 	struct atm_vcc *vcc;
@@ -2212,11 +2222,15 @@
 		return sprintf(page,"%10sbacklog %u packets\n","",
 		    skb_queue_len(&tx->backlog));
 	}
-	spin_lock_irqsave(&dev->lock, flags);
-	for (vcc = dev->vccs; vcc; vcc = vcc->next) {
-		struct eni_vcc *eni_vcc = ENI_VCC(vcc);
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+		struct eni_vcc *eni_vcc;
 		int length;
 
+		vcc = atm_sk(s);
+		if (vcc->dev != dev)
+			continue;
+		eni_vcc = ENI_VCC(vcc);
 		if (--left) continue;
 		length = sprintf(page,"vcc %4d: ",vcc->vci);
 		if (eni_vcc->rx) {
@@ -2231,10 +2245,10 @@
 			length += sprintf(page+length,"tx[%d], txing %d bytes",
 			    eni_vcc->tx->index,eni_vcc->txing);
 		page[length] = '\n';
-		spin_unlock_irqrestore(&dev->lock, flags);
+		read_unlock(&vcc_sklist_lock);
 		return length+1;
 	}
-	spin_unlock_irqrestore(&dev->lock, flags);
+	read_unlock(&vcc_sklist_lock);
 	for (i = 0; i < eni_dev->free_len; i++) {
 		struct eni_free *fe = eni_dev->free_list+i;
 		unsigned long offset;
diff -Nru a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
--- a/drivers/atm/fore200e.c	Fri Jun 20 17:33:36 2003
+++ b/drivers/atm/fore200e.c	Fri Jun 20 17:33:36 2003
@@ -1069,18 +1069,23 @@
 static struct atm_vcc* 
 fore200e_find_vcc(struct fore200e* fore200e, struct rpd* rpd)
 {
-    unsigned long flags;
+    struct sock *s;
     struct atm_vcc* vcc;
+    struct hlist_node *node;
 
-    spin_lock_irqsave(&fore200e->atm_dev->lock, flags);
-    for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) {
-
-	if (vcc->vpi == rpd->atm_header.vpi && vcc->vci == rpd->atm_header.vci)
-	    break;
+    read_lock(&vcc_sklist_lock);
+    sk_for_each(s, node, &vcc_sklist) {
+	vcc = atm_sk(s);
+	if (vcc->dev != fore200e->atm_dev)
+		continue;
+	if (vcc->vpi == rpd->atm_header.vpi && vcc->vci == rpd->atm_header.vci) {
+            read_unlock(&vcc_sklist_lock);
+	    return vcc;
+	}
     }
-    spin_unlock_irqrestore(&fore200e->atm_dev->lock, flags);
-    
-    return vcc;
+    read_unlock(&vcc_sklist_lock);
+
+    return NULL;
 }
 
 
@@ -1350,20 +1355,26 @@
 static int
 fore200e_walk_vccs(struct atm_vcc *vcc, short *vpi, int *vci)
 {
-    unsigned long flags;
     struct atm_vcc* walk;
+    struct sock *s;
+    struct hlist_node *node;
 
     /* find a free VPI */
 
-    spin_lock_irqsave(&vcc->dev->lock, flags);
+    read_lock(&vcc_sklist_lock);
 
     if (*vpi == ATM_VPI_ANY) {
 
-	for (*vpi = 0, walk = vcc->dev->vccs; walk; walk = walk->next) {
+	*vpi = 0;
+restart_vpi_search:
+	sk_for_each(s, node, &vcc_sklist) {
+	    walk = atm_sk(s);
+	    if (walk->dev != vcc->dev)
+		continue;
 
 	    if ((walk->vci == *vci) && (walk->vpi == *vpi)) {
 		(*vpi)++;
-		walk = vcc->dev->vccs;
+		goto restart_vpi_search;
 	    }
 	}
     }
@@ -1371,16 +1382,21 @@
     /* find a free VCI */
     if (*vci == ATM_VCI_ANY) {
 	
-	for (*vci = ATM_NOT_RSV_VCI, walk = vcc->dev->vccs; walk; walk = walk->next) {
+	*vci = ATM_NOT_RSV_VCI;
+restart_vci_search:
+	sk_for_each(s, node, &vcc_sklist) {
+	    walk = atm_sk(s);
+	    if (walk->dev != vcc->dev)
+		continue;
 
 	    if ((walk->vpi = *vpi) && (walk->vci == *vci)) {
 		*vci = walk->vci + 1;
-		walk = vcc->dev->vccs;
+		goto restart_vci_search;
 	    }
 	}
     }
 
-    spin_unlock_irqrestore(&vcc->dev->lock, flags);
+    read_unlock(&vcc_sklist_lock);
 
     return 0;
 }
@@ -2642,7 +2658,8 @@
 static int
 fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page)
 {
-    unsigned long flags;
+    struct sock *s;
+    struct hlist_node *node;
     struct fore200e* fore200e  = FORE200E_DEV(dev);
     int              len, left = *pos;
 
@@ -2889,8 +2906,12 @@
 	len = sprintf(page,"\n"    
 		      " VCCs:\n  address\tVPI.VCI:AAL\t(min/max tx PDU size) (min/max rx PDU size)\n");
 	
-	spin_lock_irqsave(&fore200e->atm_dev->lock, flags);
-	for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) {
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+	    vcc = atm_sk(s);
+
+	    if (vcc->dev != fore200e->atm_dev)
+		    continue;
 
 	    fore200e_vcc = FORE200E_VCC(vcc);
 	    
@@ -2904,7 +2925,7 @@
 			   fore200e_vcc->rx_max_pdu
 		);
 	}
-	spin_unlock_irqrestore(&fore200e->atm_dev->lock, flags);
+	read_unlock(&vcc_sklist_lock);
 
 	return len;
     }
diff -Nru a/drivers/atm/he.c b/drivers/atm/he.c
--- a/drivers/atm/he.c	Fri Jun 20 17:33:36 2003
+++ b/drivers/atm/he.c	Fri Jun 20 17:33:36 2003
@@ -79,7 +79,6 @@
 #include <linux/sonet.h>
 
 #define USE_TASKLET
-#define USE_HE_FIND_VCC
 #undef USE_SCATTERGATHER
 #undef USE_CHECKSUM_HW			/* still confused about this */
 #define USE_RBPS
@@ -328,25 +327,25 @@
 		he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 7)
 
 static __inline__ struct atm_vcc*
-he_find_vcc(struct he_dev *he_dev, unsigned cid)
+__find_vcc(struct he_dev *he_dev, unsigned cid)
 {
-	unsigned long flags;
 	struct atm_vcc *vcc;
+	struct hlist_node *node;
+	struct sock *s;
 	short vpi;
 	int vci;
 
 	vpi = cid >> he_dev->vcibits;
 	vci = cid & ((1 << he_dev->vcibits) - 1);
 
-	spin_lock_irqsave(&he_dev->atm_dev->lock, flags);
-	for (vcc = he_dev->atm_dev->vccs; vcc; vcc = vcc->next)
-		if (vcc->vci == vci && vcc->vpi == vpi
-			&& vcc->qos.rxtp.traffic_class != ATM_NONE) {
-				spin_unlock_irqrestore(&he_dev->atm_dev->lock, flags);
+	sk_for_each(s, node, &vcc_sklist) {
+		vcc = atm_sk(s);
+		if (vcc->dev == he_dev->atm_dev &&
+		    vcc->vci == vci && vcc->vpi == vpi &&
+		    vcc->qos.rxtp.traffic_class != ATM_NONE) {
 				return vcc;
-			}
-
-	spin_unlock_irqrestore(&he_dev->atm_dev->lock, flags);
+		}
+	}
 	return NULL;
 }
 
@@ -1566,17 +1565,6 @@
 	reg |= RX_ENABLE;
 	he_writel(he_dev, reg, RC_CONFIG);
 
-#ifndef USE_HE_FIND_VCC
-	he_dev->he_vcc_table = kmalloc(sizeof(struct he_vcc_table) * 
-			(1 << (he_dev->vcibits + he_dev->vpibits)), GFP_KERNEL);
-	if (he_dev->he_vcc_table == NULL) {
-		hprintk("failed to alloc he_vcc_table\n");
-		return -ENOMEM;
-	}
-	memset(he_dev->he_vcc_table, 0, sizeof(struct he_vcc_table) *
-				(1 << (he_dev->vcibits + he_dev->vpibits)));
-#endif
-
 	for (i = 0; i < HE_NUM_CS_STPER; ++i) {
 		he_dev->cs_stper[i].inuse = 0;
 		he_dev->cs_stper[i].pcr = -1;
@@ -1712,11 +1700,6 @@
 							he_dev->tpd_base, he_dev->tpd_base_phys);
 #endif
 
-#ifndef USE_HE_FIND_VCC
-	if (he_dev->he_vcc_table)
-		kfree(he_dev->he_vcc_table);
-#endif
-
 	if (he_dev->pci_dev) {
 		pci_read_config_word(he_dev->pci_dev, PCI_COMMAND, &command);
 		command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
@@ -1798,6 +1781,7 @@
 	int pdus_assembled = 0;
 	int updated = 0;
 
+	read_lock(&vcc_sklist_lock);
 	while (he_dev->rbrq_head != rbrq_tail) {
 		++updated;
 
@@ -1823,13 +1807,10 @@
 		buf_len = RBRQ_BUFLEN(he_dev->rbrq_head) * 4;
 		cid = RBRQ_CID(he_dev->rbrq_head);
 
-#ifdef USE_HE_FIND_VCC
 		if (cid != lastcid)
-			vcc = he_find_vcc(he_dev, cid);
+			vcc = __find_vcc(he_dev, cid);
 		lastcid = cid;
-#else
-		vcc = HE_LOOKUP_VCC(he_dev, cid);
-#endif
+
 		if (vcc == NULL) {
 			hprintk("vcc == NULL  (cid 0x%x)\n", cid);
 			if (!RBRQ_HBUF_ERR(he_dev->rbrq_head))
@@ -1966,6 +1947,7 @@
 					RBRQ_MASK(++he_dev->rbrq_head));
 
 	}
+	read_unlock(&vcc_sklist_lock);
 
 	if (updated) {
 		if (updated > he_dev->rbrq_peak)
@@ -2565,10 +2547,6 @@
 #endif
 
 		spin_unlock_irqrestore(&he_dev->global_lock, flags);
-
-#ifndef USE_HE_FIND_VCC
-		HE_LOOKUP_VCC(he_dev, cid) = vcc;
-#endif
 	}
 
 open_failed:
@@ -2634,9 +2612,6 @@
 		if (timeout == 0)
 			hprintk("close rx timeout cid 0x%x\n", cid);
 
-#ifndef USE_HE_FIND_VCC
-		HE_LOOKUP_VCC(he_dev, cid) = NULL;
-#endif
 		HPRINTK("close rx cid 0x%x complete\n", cid);
 
 	}
diff -Nru a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
--- a/drivers/atm/idt77252.c	Fri Jun 20 17:33:36 2003
+++ b/drivers/atm/idt77252.c	Fri Jun 20 17:33:36 2003
@@ -2403,37 +2403,43 @@
 static int
 idt77252_find_vcc(struct atm_vcc *vcc, short *vpi, int *vci)
 {
-	unsigned long flags;
+	struct sock *s;
 	struct atm_vcc *walk;
 
-	spin_lock_irqsave(&vcc->dev->lock, flags);
+	read_lock(&vcc_sklist_lock);
 	if (*vpi == ATM_VPI_ANY) {
 		*vpi = 0;
-		walk = vcc->dev->vccs;
-		while (walk) {
+		s = sk_head(&vcc_sklist);
+		while (s) {
+			walk = atm_sk(s);
+			if (walk->dev != vcc->dev)
+				continue;
 			if ((walk->vci == *vci) && (walk->vpi == *vpi)) {
 				(*vpi)++;
-				walk = vcc->dev->vccs;
+				s = sk_head(&vcc_sklist);
 				continue;
 			}
-			walk = walk->next;
+			s = sk_next(s);
 		}
 	}
 
 	if (*vci == ATM_VCI_ANY) {
 		*vci = ATM_NOT_RSV_VCI;
-		walk = vcc->dev->vccs;
-		while (walk) {
+		s = sk_head(&vcc_sklist);
+		while (s) {
+			walk = atm_sk(s);
+			if (walk->dev != vcc->dev)
+				continue;
 			if ((walk->vci == *vci) && (walk->vpi == *vpi)) {
 				(*vci)++;
-				walk = vcc->dev->vccs;
+				s = sk_head(&vcc_sklist);
 				continue;
 			}
-			walk = walk->next;
+			s = sk_next(s);
 		}
 	}
 
-	spin_unlock_irqrestore(&vcc->dev->lock, flags);
+	read_unlock(&vcc_sklist_lock);
 	return 0;
 }
 
diff -Nru a/include/linux/atmdev.h b/include/linux/atmdev.h
--- a/include/linux/atmdev.h	Fri Jun 20 17:33:36 2003
+++ b/include/linux/atmdev.h	Fri Jun 20 17:33:36 2003
@@ -293,7 +293,6 @@
 	struct k_atm_aal_stats *stats;	/* pointer to AAL stats group */
 	wait_queue_head_t sleep;	/* if socket is busy */
 	struct sock	*sk;		/* socket backpointer */
-	struct atm_vcc	*prev,*next;
 	/* SVC part --- may move later ------------------------------------- */
 	short		itf;		/* interface number */
 	struct sockaddr_atmsvc local;
@@ -320,8 +319,6 @@
 					/* (NULL) */
 	const char	*type;		/* device type name */
 	int		number;		/* device index */
-	struct atm_vcc	*vccs;		/* VCC table (or NULL) */
-	struct atm_vcc	*last;		/* last VCC (or undefined) */
 	void		*dev_data;	/* per-device data */
 	void		*phy_data;	/* private PHY date */
 	unsigned long	flags;		/* device flags (ATM_DF_*) */
@@ -390,6 +387,9 @@
 	unsigned long	atm_options;	/* ATM layer options */
 };
 
+extern struct hlist_head vcc_sklist;
+extern rwlock_t vcc_sklist_lock;
+
 #define ATM_SKB(skb) (((struct atm_skb_data *) (skb)->cb))
 
 struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
@@ -397,7 +397,8 @@
 struct atm_dev *atm_dev_lookup(int number);
 void atm_dev_deregister(struct atm_dev *dev);
 void shutdown_atm_dev(struct atm_dev *dev);
-void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev);
+void vcc_insert_socket(struct sock *sk);
+void vcc_remove_socket(struct sock *sk);
 
 
 /*
@@ -436,7 +437,7 @@
 }
 
 
-static inline void atm_dev_release(struct atm_dev *dev)
+static inline void atm_dev_put(struct atm_dev *dev)
 {
 	atomic_dec(&dev->refcnt);
 
diff -Nru a/net/atm/atm_misc.c b/net/atm/atm_misc.c
--- a/net/atm/atm_misc.c	Fri Jun 20 17:33:36 2003
+++ b/net/atm/atm_misc.c	Fri Jun 20 17:33:36 2003
@@ -47,15 +47,21 @@
 
 static int check_ci(struct atm_vcc *vcc,short vpi,int vci)
 {
+	struct hlist_node *node;
+	struct sock *s;
 	struct atm_vcc *walk;
 
-	for (walk = vcc->dev->vccs; walk; walk = walk->next)
+	sk_for_each(s, node, &vcc_sklist) {
+		walk = atm_sk(s);
+		if (walk->dev != vcc->dev)
+			continue;
 		if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vpi == vpi &&
 		    walk->vci == vci && ((walk->qos.txtp.traffic_class !=
 		    ATM_NONE && vcc->qos.txtp.traffic_class != ATM_NONE) ||
 		    (walk->qos.rxtp.traffic_class != ATM_NONE &&
 		    vcc->qos.rxtp.traffic_class != ATM_NONE)))
 			return -EADDRINUSE;
+	}
 		/* allow VCCs with same VPI/VCI iff they don't collide on
 		   TX/RX (but we may refuse such sharing for other reasons,
 		   e.g. if protocol requires to have both channels) */
@@ -65,17 +71,16 @@
 
 int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci)
 {
-	unsigned long flags;
 	static short p = 0; /* poor man's per-device cache */
 	static int c = 0;
 	short old_p;
 	int old_c;
 	int err;
 
-	spin_lock_irqsave(&vcc->dev->lock, flags);
+	read_lock(&vcc_sklist_lock);
 	if (*vpi != ATM_VPI_ANY && *vci != ATM_VCI_ANY) {
 		err = check_ci(vcc,*vpi,*vci);
-		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		read_unlock(&vcc_sklist_lock);
 		return err;
 	}
 	/* last scan may have left values out of bounds for current device */
@@ -90,7 +95,7 @@
 		if (!check_ci(vcc,p,c)) {
 			*vpi = p;
 			*vci = c;
-			spin_unlock_irqrestore(&vcc->dev->lock, flags);
+			read_unlock(&vcc_sklist_lock);
 			return 0;
 		}
 		if (*vci == ATM_VCI_ANY) {
@@ -105,7 +110,7 @@
 		}
 	}
 	while (old_p != p || old_c != c);
-	spin_unlock_irqrestore(&vcc->dev->lock, flags);
+	read_unlock(&vcc_sklist_lock);
 	return -EADDRINUSE;
 }
 
diff -Nru a/net/atm/clip.c b/net/atm/clip.c
--- a/net/atm/clip.c	Fri Jun 20 17:33:36 2003
+++ b/net/atm/clip.c	Fri Jun 20 17:33:36 2003
@@ -737,7 +737,8 @@
 	set_bit(ATM_VF_META,&vcc->flags);
 	set_bit(ATM_VF_READY,&vcc->flags);
 	    /* allow replies and avoid getting closed if signaling dies */
-	bind_vcc(vcc,&atmarpd_dev);
+	vcc->dev = &atmarpd_dev;
+	vcc_insert_socket(vcc->sk);
 	vcc->push = NULL;
 	vcc->pop = NULL; /* crash */
 	vcc->push_oam = NULL; /* crash */
diff -Nru a/net/atm/common.c b/net/atm/common.c
--- a/net/atm/common.c	Fri Jun 20 17:33:36 2003
+++ b/net/atm/common.c	Fri Jun 20 17:33:36 2003
@@ -157,6 +157,29 @@
 #endif
 
 
+HLIST_HEAD(vcc_sklist);
+rwlock_t vcc_sklist_lock = RW_LOCK_UNLOCKED;
+
+void __vcc_insert_socket(struct sock *sk)
+{
+	sk_add_node(sk, &vcc_sklist);
+}
+
+void vcc_insert_socket(struct sock *sk)
+{
+	write_lock_irq(&vcc_sklist_lock);
+	__vcc_insert_socket(sk);
+	write_unlock_irq(&vcc_sklist_lock);
+}
+
+void vcc_remove_socket(struct sock *sk)
+{
+	write_lock_irq(&vcc_sklist_lock);
+	sk_del_node_init(sk);
+	write_unlock_irq(&vcc_sklist_lock);
+}
+
+
 static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
 {
 	struct sk_buff *skb;
@@ -175,16 +198,45 @@
 }
 
 
-int atm_create(struct socket *sock,int protocol,int family)
+EXPORT_SYMBOL(vcc_sklist);
+EXPORT_SYMBOL(vcc_sklist_lock);
+EXPORT_SYMBOL(vcc_insert_socket);
+EXPORT_SYMBOL(vcc_remove_socket);
+
+static void vcc_sock_destruct(struct sock *sk)
+{
+	struct atm_vcc *vcc = atm_sk(sk);
+
+	if (atomic_read(&vcc->sk->sk_rmem_alloc))
+		printk(KERN_DEBUG "vcc_sock_destruct: rmem leakage (%d bytes) detected.\n", atomic_read(&sk->sk_rmem_alloc));
+
+	if (atomic_read(&vcc->sk->sk_wmem_alloc))
+		printk(KERN_DEBUG "vcc_sock_destruct: wmem leakage (%d bytes) detected.\n", atomic_read(&sk->sk_wmem_alloc));
+
+	kfree(sk->sk_protinfo);
+}
+ 
+int vcc_create(struct socket *sock, int protocol, int family)
 {
 	struct sock *sk;
 	struct atm_vcc *vcc;
 
 	sock->sk = NULL;
-	if (sock->type == SOCK_STREAM) return -EINVAL;
-	if (!(sk = alloc_atm_vcc_sk(family))) return -ENOMEM;
-	vcc = atm_sk(sk);
-	memset(&vcc->flags,0,sizeof(vcc->flags));
+	if (sock->type == SOCK_STREAM)
+		return -EINVAL;
+	sk = sk_alloc(family, GFP_KERNEL, 1, NULL);
+	if (!sk)
+		return -ENOMEM;
+	sock_init_data(NULL, sk);
+
+	vcc = atm_sk(sk) = kmalloc(sizeof(*vcc), GFP_KERNEL);
+	if (!vcc) {
+		sk_free(sk);
+		return -ENOMEM;
+	}
+
+	memset(vcc, 0, sizeof(*vcc));
+	vcc->sk = sk;
 	vcc->dev = NULL;
 	vcc->callback = NULL;
 	memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc));
@@ -199,42 +251,48 @@
 	vcc->atm_options = vcc->aal_options = 0;
 	init_waitqueue_head(&vcc->sleep);
 	sk->sk_sleep = &vcc->sleep;
+	sk->sk_destruct = vcc_sock_destruct;
 	sock->sk = sk;
 	return 0;
 }
 
 
-void atm_release_vcc_sk(struct sock *sk,int free_sk)
+static void vcc_destroy_socket(struct sock *sk)
 {
 	struct atm_vcc *vcc = atm_sk(sk);
 	struct sk_buff *skb;
 
-	clear_bit(ATM_VF_READY,&vcc->flags);
+	clear_bit(ATM_VF_READY, &vcc->flags);
 	if (vcc->dev) {
-		if (vcc->dev->ops->close) vcc->dev->ops->close(vcc);
-		if (vcc->push) vcc->push(vcc,NULL); /* atmarpd has no push */
+		if (vcc->dev->ops->close)
+			vcc->dev->ops->close(vcc);
+		if (vcc->push)
+			vcc->push(vcc, NULL); /* atmarpd has no push */
+
+		vcc_remove_socket(sk);	/* no more receive */
+
 		while ((skb = skb_dequeue(&vcc->sk->sk_receive_queue))) {
 			atm_return(vcc,skb->truesize);
 			kfree_skb(skb);
 		}
 
 		module_put(vcc->dev->ops->owner);
-		atm_dev_release(vcc->dev);
-		if (atomic_read(&vcc->sk->sk_rmem_alloc))
-			printk(KERN_WARNING "atm_release_vcc: strange ... "
-			    "rmem_alloc == %d after closing\n",
-			    atomic_read(&vcc->sk->sk_rmem_alloc));
-		bind_vcc(vcc,NULL);
+		atm_dev_put(vcc->dev);
 	}
-
-	if (free_sk) free_atm_vcc_sk(sk);
 }
 
 
-int atm_release(struct socket *sock)
+int vcc_release(struct socket *sock)
 {
-	if (sock->sk)
-		atm_release_vcc_sk(sock->sk,1);
+	struct sock *sk = sock->sk;
+
+	if (sk) {
+		lock_sock(sk);
+		vcc_destroy_socket(sock->sk);
+		release_sock(sk);
+		sock_put(sk);
+	}
+
 	return 0;
 }
 
@@ -289,7 +347,8 @@
 	if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE))
 		return -EPERM;
 	error = 0;
-	bind_vcc(vcc,dev);
+	vcc->dev = dev;
+	vcc_insert_socket(vcc->sk);
 	switch (vcc->qos.aal) {
 		case ATM_AAL0:
 			error = atm_init_aal0(vcc);
@@ -313,7 +372,7 @@
 	if (!error) error = adjust_tp(&vcc->qos.txtp,vcc->qos.aal);
 	if (!error) error = adjust_tp(&vcc->qos.rxtp,vcc->qos.aal);
 	if (error) {
-		bind_vcc(vcc,NULL);
+		vcc_remove_socket(vcc->sk);
 		return error;
 	}
 	DPRINTK("VCC %d.%d, AAL %d\n",vpi,vci,vcc->qos.aal);
@@ -327,7 +386,7 @@
 		error = dev->ops->open(vcc,vpi,vci);
 		if (error) {
 			module_put(dev->ops->owner);
-			bind_vcc(vcc,NULL);
+			vcc_remove_socket(vcc->sk);
 			return error;
 		}
 	}
@@ -371,7 +430,7 @@
 		dev = atm_dev_lookup(itf);
 		error = __vcc_connect(vcc, dev, vpi, vci);
 		if (error) {
-			atm_dev_release(dev);
+			atm_dev_put(dev);
 			return error;
 		}
 	} else {
@@ -385,7 +444,7 @@
 			spin_unlock(&atm_dev_lock);
 			if (!__vcc_connect(vcc, dev, vpi, vci))
 				break;
-			atm_dev_release(dev);
+			atm_dev_put(dev);
 			dev = NULL;
 			spin_lock(&atm_dev_lock);
 		}
diff -Nru a/net/atm/common.h b/net/atm/common.h
--- a/net/atm/common.h	Fri Jun 20 17:33:36 2003
+++ b/net/atm/common.h	Fri Jun 20 17:33:36 2003
@@ -10,8 +10,8 @@
 #include <linux/poll.h> /* for poll_table */
 
 
-int atm_create(struct socket *sock,int protocol,int family);
-int atm_release(struct socket *sock);
+int vcc_create(struct socket *sock, int protocol, int family);
+int vcc_release(struct socket *sock);
 int vcc_connect(struct socket *sock, int itf, short vpi, int vci);
 int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
 		int size, int flags);
@@ -24,7 +24,6 @@
 int vcc_getsockopt(struct socket *sock, int level, int optname, char *optval,
 		   int *optlen);
 
-void atm_release_vcc_sk(struct sock *sk,int free_sk);
 void atm_shutdown_dev(struct atm_dev *dev);
 
 int atmpvc_init(void);
diff -Nru a/net/atm/lec.c b/net/atm/lec.c
--- a/net/atm/lec.c	Fri Jun 20 17:33:36 2003
+++ b/net/atm/lec.c	Fri Jun 20 17:33:36 2003
@@ -48,7 +48,7 @@
 
 #include "lec.h"
 #include "lec_arpc.h"
-#include "resources.h"  /* for bind_vcc() */
+#include "resources.h"
 
 #if 0
 #define DPRINTK printk
@@ -810,7 +810,8 @@
         lec_arp_init(priv);
 	priv->itfnum = i;  /* LANE2 addition */
         priv->lecd = vcc;
-        bind_vcc(vcc, &lecatm_dev);
+        vcc->dev = &lecatm_dev;
+        vcc_insert_socket(vcc->sk);
         
         vcc->proto_data = dev_lec[i];
 	set_bit(ATM_VF_META,&vcc->flags);
diff -Nru a/net/atm/mpc.c b/net/atm/mpc.c
--- a/net/atm/mpc.c	Fri Jun 20 17:33:36 2003
+++ b/net/atm/mpc.c	Fri Jun 20 17:33:36 2003
@@ -28,7 +28,7 @@
 
 #include "lec.h"
 #include "mpc.h"
-#include "resources.h"  /* for bind_vcc() */
+#include "resources.h"
 
 /*
  * mpc.c: Implementation of MPOA client kernel part 
@@ -789,7 +789,8 @@
 	}
 
 	mpc->mpoad_vcc = vcc;
-	bind_vcc(vcc, &mpc_dev);
+	vcc->dev = &mpc_dev;
+	vcc_insert_socket(vcc->sk);
 	set_bit(ATM_VF_META,&vcc->flags);
 	set_bit(ATM_VF_READY,&vcc->flags);
 
diff -Nru a/net/atm/proc.c b/net/atm/proc.c
--- a/net/atm/proc.c	Fri Jun 20 17:33:36 2003
+++ b/net/atm/proc.c	Fri Jun 20 17:33:36 2003
@@ -334,9 +334,8 @@
 
 static int atm_pvc_info(loff_t pos,char *buf)
 {
-	unsigned long flags;
-	struct atm_dev *dev;
-	struct list_head *p;
+	struct hlist_node *node;
+	struct sock *s;
 	struct atm_vcc *vcc;
 	int left, clip_info = 0;
 
@@ -349,25 +348,20 @@
 	if (try_atm_clip_ops())
 		clip_info = 1;
 #endif
-	spin_lock(&atm_dev_lock);
-	list_for_each(p, &atm_devs) {
-		dev = list_entry(p, struct atm_dev, dev_list);
-		spin_lock_irqsave(&dev->lock, flags);
-		for (vcc = dev->vccs; vcc; vcc = vcc->next)
-			if (vcc->sk->sk_family == PF_ATMPVC &&
-			    vcc->dev && !left--) {
-				pvc_info(vcc,buf,clip_info);
-				spin_unlock_irqrestore(&dev->lock, flags);
-				spin_unlock(&atm_dev_lock);
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+		vcc = atm_sk(s);
+		if (vcc->sk->sk_family == PF_ATMPVC && vcc->dev && !left--) {
+			pvc_info(vcc,buf,clip_info);
+			read_unlock(&vcc_sklist_lock);
 #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
-				if (clip_info)
-					module_put(atm_clip_ops->owner);
+			if (clip_info)
+				module_put(atm_clip_ops->owner);
 #endif
-				return strlen(buf);
-			}
-		spin_unlock_irqrestore(&dev->lock, flags);
+			return strlen(buf);
+		}
 	}
-	spin_unlock(&atm_dev_lock);
+	read_unlock(&vcc_sklist_lock);
 #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
 	if (clip_info)
 		module_put(atm_clip_ops->owner);
@@ -378,10 +372,9 @@
 
 static int atm_vc_info(loff_t pos,char *buf)
 {
-	unsigned long flags;
-	struct atm_dev *dev;
-	struct list_head *p;
 	struct atm_vcc *vcc;
+	struct hlist_node *node;
+	struct sock *s;
 	int left;
 
 	if (!pos)
@@ -389,20 +382,16 @@
 		    "Address"," Itf VPI VCI   Fam Flags Reply Send buffer"
 		    "     Recv buffer\n");
 	left = pos-1;
-	spin_lock(&atm_dev_lock);
-	list_for_each(p, &atm_devs) {
-		dev = list_entry(p, struct atm_dev, dev_list);
-		spin_lock_irqsave(&dev->lock, flags);
-		for (vcc = dev->vccs; vcc; vcc = vcc->next)
-			if (!left--) {
-				vc_info(vcc,buf);
-				spin_unlock_irqrestore(&dev->lock, flags);
-				spin_unlock(&atm_dev_lock);
-				return strlen(buf);
-			}
-		spin_unlock_irqrestore(&dev->lock, flags);
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+		vcc = atm_sk(s);
+		if (!left--) {
+			vc_info(vcc,buf);
+			read_unlock(&vcc_sklist_lock);
+			return strlen(buf);
+		}
 	}
-	spin_unlock(&atm_dev_lock);
+	read_unlock(&vcc_sklist_lock);
 
 	return 0;
 }
@@ -410,29 +399,24 @@
 
 static int atm_svc_info(loff_t pos,char *buf)
 {
-	unsigned long flags;
-	struct atm_dev *dev;
-	struct list_head *p;
+	struct hlist_node *node;
+	struct sock *s;
 	struct atm_vcc *vcc;
 	int left;
 
 	if (!pos)
 		return sprintf(buf,"Itf VPI VCI           State      Remote\n");
 	left = pos-1;
-	spin_lock(&atm_dev_lock);
-	list_for_each(p, &atm_devs) {
-		dev = list_entry(p, struct atm_dev, dev_list);
-		spin_lock_irqsave(&dev->lock, flags);
-		for (vcc = dev->vccs; vcc; vcc = vcc->next)
-			if (vcc->sk->sk_family == PF_ATMSVC && !left--) {
-				svc_info(vcc,buf);
-				spin_unlock_irqrestore(&dev->lock, flags);
-				spin_unlock(&atm_dev_lock);
-				return strlen(buf);
-			}
-		spin_unlock_irqrestore(&dev->lock, flags);
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+		vcc = atm_sk(s);
+		if (vcc->sk->sk_family == PF_ATMSVC && !left--) {
+			svc_info(vcc,buf);
+			read_unlock(&vcc_sklist_lock);
+			return strlen(buf);
+		}
 	}
-	spin_unlock(&atm_dev_lock);
+	read_unlock(&vcc_sklist_lock);
 
 	return 0;
 }
diff -Nru a/net/atm/pvc.c b/net/atm/pvc.c
--- a/net/atm/pvc.c	Fri Jun 20 17:33:36 2003
+++ b/net/atm/pvc.c	Fri Jun 20 17:33:36 2003
@@ -17,10 +17,6 @@
 #include "resources.h"		/* devs and vccs */
 #include "common.h"		/* common for PVCs and SVCs */
 
-#ifndef NULL
-#define NULL 0
-#endif
-
 
 static int pvc_shutdown(struct socket *sock,int how)
 {
@@ -109,7 +105,7 @@
 static struct proto_ops pvc_proto_ops = {
 	.family =	PF_ATMPVC,
 
-	.release =	atm_release,
+	.release =	vcc_release,
 	.bind =		pvc_bind,
 	.connect =	pvc_connect,
 	.socketpair =	sock_no_socketpair,
@@ -131,7 +127,7 @@
 static int pvc_create(struct socket *sock,int protocol)
 {
 	sock->ops = &pvc_proto_ops;
-	return atm_create(sock,protocol,PF_ATMPVC);
+	return vcc_create(sock, protocol, PF_ATMPVC);
 }
 
 
diff -Nru a/net/atm/resources.c b/net/atm/resources.c
--- a/net/atm/resources.c	Fri Jun 20 17:33:36 2003
+++ b/net/atm/resources.c	Fri Jun 20 17:33:36 2003
@@ -23,11 +23,6 @@
 #include "addr.h"
 
 
-#ifndef NULL
-#define NULL 0
-#endif
-
-
 LIST_HEAD(atm_devs);
 spinlock_t atm_dev_lock = SPIN_LOCK_UNLOCKED;
 
@@ -91,7 +86,7 @@
 	spin_lock(&atm_dev_lock);
 	if (number != -1) {
 		if ((inuse = __atm_dev_lookup(number))) {
-			atm_dev_release(inuse);
+			atm_dev_put(inuse);
 			spin_unlock(&atm_dev_lock);
 			__free_atm_dev(dev);
 			return NULL;
@@ -100,7 +95,7 @@
 	} else {
 		dev->number = 0;
 		while ((inuse = __atm_dev_lookup(dev->number))) {
-			atm_dev_release(inuse);
+			atm_dev_put(inuse);
 			dev->number++;
 		}
 	}
@@ -402,78 +397,12 @@
 	else
 		error = 0;
 done:
-	atm_dev_release(dev);
+	atm_dev_put(dev);
 	return error;
 }
 
 
-struct sock *alloc_atm_vcc_sk(int family)
-{
-	struct sock *sk;
-	struct atm_vcc *vcc;
-
-	sk = sk_alloc(family, GFP_KERNEL, 1, NULL);
-	if (!sk)
-		return NULL;
-	vcc = atm_sk(sk) = kmalloc(sizeof(*vcc), GFP_KERNEL);
-	if (!vcc) {
-		sk_free(sk);
-		return NULL;
-	}
-	sock_init_data(NULL, sk);
-	memset(vcc, 0, sizeof(*vcc));
-	vcc->sk = sk;
-
-	return sk;
-}
-
-
-static void unlink_vcc(struct atm_vcc *vcc)
-{
-	unsigned long flags;
-	if (vcc->dev) {
-		spin_lock_irqsave(&vcc->dev->lock, flags);
-		if (vcc->prev)
-			vcc->prev->next = vcc->next;
-		else
-			vcc->dev->vccs = vcc->next;
-
-		if (vcc->next)
-			vcc->next->prev = vcc->prev;
-		else
-			vcc->dev->last = vcc->prev;
-		spin_unlock_irqrestore(&vcc->dev->lock, flags);
-	}
-}
-
-
-void free_atm_vcc_sk(struct sock *sk)
-{
-	unlink_vcc(atm_sk(sk));
-	sk_free(sk);
-}
-
-void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev)
-{
-	unsigned long flags;
-
-	unlink_vcc(vcc);
-	vcc->dev = dev;
-	if (dev) {
-		spin_lock_irqsave(&dev->lock, flags);
-		vcc->next = NULL;
-		vcc->prev = dev->last;
-		if (dev->vccs)
-			dev->last->next = vcc;
-		else
-			dev->vccs = vcc;
-		dev->last = vcc;
-		spin_unlock_irqrestore(&dev->lock, flags);
-	}
-}
-
 EXPORT_SYMBOL(atm_dev_register);
 EXPORT_SYMBOL(atm_dev_deregister);
 EXPORT_SYMBOL(atm_dev_lookup);
 EXPORT_SYMBOL(shutdown_atm_dev);
-EXPORT_SYMBOL(bind_vcc);
diff -Nru a/net/atm/resources.h b/net/atm/resources.h
--- a/net/atm/resources.h	Fri Jun 20 17:33:36 2003
+++ b/net/atm/resources.h	Fri Jun 20 17:33:36 2003
@@ -14,8 +14,6 @@
 extern spinlock_t atm_dev_lock;
 
 
-struct sock *alloc_atm_vcc_sk(int family);
-void free_atm_vcc_sk(struct sock *sk);
 int atm_dev_ioctl(unsigned int cmd, unsigned long arg);
 
 
diff -Nru a/net/atm/signaling.c b/net/atm/signaling.c
--- a/net/atm/signaling.c	Fri Jun 20 17:33:36 2003
+++ b/net/atm/signaling.c	Fri Jun 20 17:33:36 2003
@@ -200,26 +200,22 @@
 }
 
 
-static void purge_vccs(struct atm_vcc *vcc)
+static void purge_vcc(struct atm_vcc *vcc)
 {
-	while (vcc) {
-		if (vcc->sk->sk_family == PF_ATMSVC &&
-		    !test_bit(ATM_VF_META,&vcc->flags)) {
-			set_bit(ATM_VF_RELEASED,&vcc->flags);
-			vcc->reply = -EUNATCH;
-			vcc->sk->sk_err = EUNATCH;
-			wake_up(&vcc->sleep);
-		}
-		vcc = vcc->next;
+	if (vcc->sk->sk_family == PF_ATMSVC &&
+	    !test_bit(ATM_VF_META,&vcc->flags)) {
+		set_bit(ATM_VF_RELEASED,&vcc->flags);
+		vcc->reply = -EUNATCH;
+		vcc->sk->sk_err = EUNATCH;
+		wake_up(&vcc->sleep);
 	}
 }
 
 
 static void sigd_close(struct atm_vcc *vcc)
 {
-	unsigned long flags;
-	struct atm_dev *dev;
-	struct list_head *p;
+	struct hlist_node *node;
+	struct sock *s;
 
 	DPRINTK("sigd_close\n");
 	sigd = NULL;
@@ -227,14 +223,14 @@
 		printk(KERN_ERR "sigd_close: closing with requests pending\n");
 	skb_queue_purge(&vcc->sk->sk_receive_queue);
 
-	spin_lock(&atm_dev_lock);
-	list_for_each(p, &atm_devs) {
-		dev = list_entry(p, struct atm_dev, dev_list);
-		spin_lock_irqsave(&dev->lock, flags);
-		purge_vccs(dev->vccs);
-		spin_unlock_irqrestore(&dev->lock, flags);
+	read_lock(&vcc_sklist_lock);
+	sk_for_each(s, node, &vcc_sklist) {
+		struct atm_vcc *vcc = atm_sk(s);
+
+		if (vcc->dev)
+			purge_vcc(vcc);
 	}
-	spin_unlock(&atm_dev_lock);
+	read_unlock(&vcc_sklist_lock);
 }
 
 
@@ -257,7 +253,8 @@
 	if (sigd) return -EADDRINUSE;
 	DPRINTK("sigd_attach\n");
 	sigd = vcc;
-	bind_vcc(vcc,&sigd_dev);
+	vcc->dev = &sigd_dev;
+	vcc_insert_socket(vcc->sk);
 	set_bit(ATM_VF_META,&vcc->flags);
 	set_bit(ATM_VF_READY,&vcc->flags);
 	wake_up(&sigd_sleep);
diff -Nru a/net/atm/svc.c b/net/atm/svc.c
--- a/net/atm/svc.c	Fri Jun 20 17:33:36 2003
+++ b/net/atm/svc.c	Fri Jun 20 17:33:36 2003
@@ -88,18 +88,21 @@
 
 static int svc_release(struct socket *sock)
 {
+	struct sock *sk = sock->sk;
 	struct atm_vcc *vcc;
 
-	if (!sock->sk) return 0;
-	vcc = ATM_SD(sock);
-	DPRINTK("svc_release %p\n",vcc);
-	clear_bit(ATM_VF_READY,&vcc->flags);
-	atm_release_vcc_sk(sock->sk,0);
-	svc_disconnect(vcc);
-	    /* VCC pointer is used as a reference, so we must not free it
-	       (thereby subjecting it to re-use) before all pending connections
-	        are closed */
-	free_atm_vcc_sk(sock->sk);
+	if (sk)  {
+		vcc = ATM_SD(sock);
+		DPRINTK("svc_release %p\n", vcc);
+		clear_bit(ATM_VF_READY, &vcc->flags);
+		/* VCC pointer is used as a reference, so we must not free it
+		   (thereby subjecting it to re-use) before all pending connections
+	           are closed */
+		sock_hold(sk);
+		vcc_release(sock);
+		svc_disconnect(vcc);
+		sock_put(sk);
+	}
 	return 0;
 }
 
@@ -542,7 +545,7 @@
 	int error;
 
 	sock->ops = &svc_proto_ops;
-	error = atm_create(sock,protocol,AF_ATMSVC);
+	error = vcc_create(sock, protocol, AF_ATMSVC);
 	if (error) return error;
 	ATM_SD(sock)->callback = svc_callback;
 	ATM_SD(sock)->local.sas_family = AF_ATMSVC;

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

end of thread, other threads:[~2003-06-20 21:32 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-06-17 12:40 [PATCH][ATM][3/3] assorted changes for atm chas williams
2003-06-17 17:31 ` David S. Miller
2003-06-18 15:24   ` chas williams
2003-06-20 20:53   ` chas williams
2003-06-20 21:32     ` chas williams

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).