patch-2.3.6 linux/net/core/dev_mcast.c
Next file: linux/net/core/dst.c
Previous file: linux/net/core/dev.c
Back to the patch index
Back to the overall index
- Lines: 157
- Date:
Wed Jun 9 14:45:36 1999
- Orig file:
v2.3.5/linux/net/core/dev_mcast.c
- Orig date:
Mon May 31 22:28:07 1999
diff -u --recursive --new-file v2.3.5/linux/net/core/dev_mcast.c linux/net/core/dev_mcast.c
@@ -58,7 +58,11 @@
*
* Device mc lists are changed by bh at least if IPv6 is enabled,
* so that it must be bh protected.
+ *
+ * We protect all mc lists with global rw lock
+ * and block accesses to device mc filters with dev->xmit_lock.
*/
+static rwlock_t dev_mc_lock = RW_LOCK_UNLOCKED;
/*
* Update the multicast list into the physical NIC controller.
@@ -69,7 +73,7 @@
/* Don't do anything till we up the interface
[dev_open will call this function so the list will
stay sane] */
-
+
if(!(dev->flags&IFF_UP))
return;
@@ -80,11 +84,15 @@
if(dev->set_multicast_list==NULL)
return;
- start_bh_atomic();
+ read_lock_bh(&dev_mc_lock);
+ spin_lock(&dev->xmit_lock);
+ dev->xmit_lock_owner = smp_processor_id();
dev->set_multicast_list(dev);
- end_bh_atomic();
+ dev->xmit_lock_owner = -1;
+ spin_unlock(&dev->xmit_lock);
+ read_unlock_bh(&dev_mc_lock);
}
-
+
/*
* Delete a device level multicast
*/
@@ -94,7 +102,7 @@
int err = 0;
struct dev_mc_list *dmi, **dmip;
- start_bh_atomic();
+ write_lock_bh(&dev_mc_lock);
for (dmip=&dev->mc_list; (dmi=*dmip)!=NULL; dmip=&dmi->next) {
/*
* Find the entry we want to delete. The device could
@@ -120,14 +128,15 @@
* We have altered the list, so the card
* loaded filter is now wrong. Fix it
*/
- end_bh_atomic();
+ write_unlock_bh(&dev_mc_lock);
+
dev_mc_upload(dev);
return 0;
}
}
err = -ENOENT;
done:
- end_bh_atomic();
+ write_unlock_bh(&dev_mc_lock);
return err;
}
@@ -140,9 +149,12 @@
int err = 0;
struct dev_mc_list *dmi, *dmi1;
+ /* RED-PEN: does gfp_any() work now? It requires
+ true local_bh_disable rather than global.
+ */
dmi1 = (struct dev_mc_list *)kmalloc(sizeof(*dmi), gfp_any());
- start_bh_atomic();
+ write_lock_bh(&dev_mc_lock);
for(dmi=dev->mc_list; dmi!=NULL; dmi=dmi->next) {
if (memcmp(dmi->dmi_addr,addr,dmi->dmi_addrlen)==0 && dmi->dmi_addrlen==alen) {
if (glbl) {
@@ -156,8 +168,10 @@
}
}
- if ((dmi=dmi1)==NULL)
+ if ((dmi=dmi1)==NULL) {
+ write_unlock_bh(&dev_mc_lock);
return -ENOMEM;
+ }
memcpy(dmi->dmi_addr, addr, alen);
dmi->dmi_addrlen=alen;
dmi->next=dev->mc_list;
@@ -165,12 +179,12 @@
dmi->dmi_gusers=glbl ? 1 : 0;
dev->mc_list=dmi;
dev->mc_count++;
- end_bh_atomic();
+ write_unlock_bh(&dev_mc_lock);
dev_mc_upload(dev);
return 0;
done:
- end_bh_atomic();
+ write_unlock_bh(&dev_mc_lock);
if (dmi1)
kfree(dmi1);
return err;
@@ -182,7 +196,7 @@
void dev_mc_discard(struct device *dev)
{
- start_bh_atomic();
+ write_lock_bh(&dev_mc_lock);
while (dev->mc_list!=NULL) {
struct dev_mc_list *tmp=dev->mc_list;
dev->mc_list=tmp->next;
@@ -191,7 +205,7 @@
kfree_s(tmp,sizeof(*tmp));
}
dev->mc_count=0;
- end_bh_atomic();
+ write_unlock_bh(&dev_mc_lock);
}
#ifdef CONFIG_PROC_FS
@@ -203,8 +217,9 @@
int len=0;
struct device *dev;
- read_lock_bh(&dev_base_lock);
+ read_lock(&dev_base_lock);
for (dev = dev_base; dev; dev = dev->next) {
+ read_lock_bh(&dev_mc_lock);
for (m = dev->mc_list; m; m = m->next) {
int i;
@@ -221,14 +236,17 @@
len=0;
begin=pos;
}
- if (pos > offset+length)
+ if (pos > offset+length) {
+ read_unlock_bh(&dev_mc_lock);
goto done;
+ }
}
+ read_unlock_bh(&dev_mc_lock);
}
*eof = 1;
done:
- read_unlock_bh(&dev_base_lock);
+ read_unlock(&dev_base_lock);
*start=buffer+(offset-begin);
len-=(offset-begin);
if(len>length)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)