patch-2.2.4 linux/net/core/dev_mcast.c
Next file: linux/net/core/filter.c
Previous file: linux/net/core/dev.c
Back to the patch index
Back to the overall index
- Lines: 167
- Date:
Sun Mar 21 07:22:00 1999
- Orig file:
v2.2.3/linux/net/core/dev_mcast.c
- Orig date:
Mon Jan 12 15:28:19 1998
diff -u --recursive --new-file v2.2.3/linux/net/core/dev_mcast.c linux/net/core/dev_mcast.c
@@ -56,10 +56,9 @@
* protocols without doing damage to the protocols when it deletes the
* entries. It also helps IP as it tracks overlapping maps.
*
- * BUGGGG! IPv6 calls dev_mac_add/delete from BH, it means
- * that all the functions in this file are racy. [NOT FIXED] --ANK
+ * Device mc lists are changed by bh at least if IPv6 is enabled,
+ * so that it must be bh protected.
*/
-
/*
* Update the multicast list into the physical NIC controller.
@@ -77,11 +76,13 @@
/*
* Devices with no set multicast don't get set
*/
-
+
if(dev->set_multicast_list==NULL)
return;
-
+
+ start_bh_atomic();
dev->set_multicast_list(dev);
+ end_bh_atomic();
}
/*
@@ -90,8 +91,10 @@
int dev_mc_delete(struct device *dev, void *addr, int alen, int glbl)
{
+ int err = 0;
struct dev_mc_list *dmi, **dmip;
+ start_bh_atomic();
for (dmip=&dev->mc_list; (dmi=*dmip)!=NULL; dmip=&dmi->next) {
/*
* Find the entry we want to delete. The device could
@@ -102,10 +105,10 @@
int old_glbl = dmi->dmi_gusers;
dmi->dmi_gusers = 0;
if (old_glbl == 0)
- return -ENOENT;
+ break;
}
if(--dmi->dmi_users)
- return 0;
+ goto done;
/*
* Last user. So delete the entry.
@@ -117,11 +120,15 @@
* We have altered the list, so the card
* loaded filter is now wrong. Fix it
*/
+ end_bh_atomic();
dev_mc_upload(dev);
return 0;
}
}
- return -ENOENT;
+ err = -ENOENT;
+done:
+ end_bh_atomic();
+ return err;
}
/*
@@ -130,30 +137,27 @@
int dev_mc_add(struct device *dev, void *addr, int alen, int glbl)
{
- struct dev_mc_list *dmi;
+ int err = 0;
+ struct dev_mc_list *dmi, *dmi1;
+
+ dmi1 = (struct dev_mc_list *)kmalloc(sizeof(*dmi), gfp_any());
+ start_bh_atomic();
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) {
int old_glbl = dmi->dmi_gusers;
dmi->dmi_gusers = 1;
if (old_glbl)
- return 0;
+ goto done;
}
dmi->dmi_users++;
- return 0;
+ goto done;
}
}
- /* GFP_ATOMIC!! It is used by IPv6 from interrupt,
- when new address arrives.
-
- Particularly, it means that this part of code is weirdly
- racy, and needs numerous *_bh_atomic --ANK
- */
- dmi=(struct dev_mc_list *)kmalloc(sizeof(*dmi), GFP_ATOMIC);
- if (dmi==NULL)
- return -ENOBUFS;
+ if ((dmi=dmi1)==NULL)
+ return -ENOMEM;
memcpy(dmi->dmi_addr, addr, alen);
dmi->dmi_addrlen=alen;
dmi->next=dev->mc_list;
@@ -161,8 +165,15 @@
dmi->dmi_gusers=glbl ? 1 : 0;
dev->mc_list=dmi;
dev->mc_count++;
+ end_bh_atomic();
dev_mc_upload(dev);
return 0;
+
+done:
+ end_bh_atomic();
+ if (dmi1)
+ kfree(dmi1);
+ return err;
}
/*
@@ -171,6 +182,7 @@
void dev_mc_discard(struct device *dev)
{
+ start_bh_atomic();
while (dev->mc_list!=NULL) {
struct dev_mc_list *tmp=dev->mc_list;
dev->mc_list=tmp->next;
@@ -179,6 +191,7 @@
kfree_s(tmp,sizeof(*tmp));
}
dev->mc_count=0;
+ end_bh_atomic();
}
#ifdef CONFIG_PROC_FS
@@ -189,7 +202,9 @@
struct dev_mc_list *m;
int len=0;
struct device *dev;
-
+
+ start_bh_atomic();
+
for (dev = dev_base; dev; dev = dev->next) {
for (m = dev->mc_list; m; m = m->next) {
int i;
@@ -214,10 +229,13 @@
*eof = 1;
done:
+ end_bh_atomic();
*start=buffer+(offset-begin);
len-=(offset-begin);
if(len>length)
len=length;
+ if(len<0)
+ len=0;
return len;
}
#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)