summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Zumbiehl <florz@florz.de>2007-04-20 16:57:27 -0700
committerDavid S. Miller <davem@sunset.davemloft.net>2007-04-25 22:29:19 -0700
commit74b885cf86def9bc836772e3c1788c00b72a35c9 (patch)
tree2397bcd487363cdda290c71856af59f0e6cf2ffe
parentbfafb26e11849fe99e03cc1902a91f7f65354e47 (diff)
downloadlinux-3.10-74b885cf86def9bc836772e3c1788c00b72a35c9.tar.gz
linux-3.10-74b885cf86def9bc836772e3c1788c00b72a35c9.tar.bz2
linux-3.10-74b885cf86def9bc836772e3c1788c00b72a35c9.zip
[PPPOE]: race between interface going down and connect()
below you find a patch that (hopefully) fixes a race between an interface going down and a connect() to a peer on that interface. Before, connect() would determine that an interface is up, then the interface could go down and all entries referring to that interface in the item_hash_table would be marked as ZOMBIEs and their references to the device would be freed, and after that, connect() would put a new entry into the hash table referring to the device that meanwhile is down already - which also would cause unregister_netdevice() to wait until the socket has been release()d. This patch does not suffice if we are not allowed to accept connect()s referring to a device that we already acked a NETDEV_GOING_DOWN for (that is: all references are only guaranteed to be freed after NETDEV_DOWN has been acknowledged, not necessarily after the NETDEV_GOING_DOWN already). And if we are allowed to, we could avoid looking through the hash table upon NETDEV_GOING_DOWN completely and only do that once we get the NETDEV_DOWN ... mostrows: pppoe_flush_dev is called on NETDEV_GOING_DOWN and NETDEV_DOWN to deal with this "late connect" issue. Ideally one would hope to notify users at the "NETDEV_GOING_DOWN" phase (just to pretend to be nice). However, it is the NETDEV_DOWN scan that takes all the responsibility for ensuring nobody is hanging around at that time. Signed-off-by: Florian Zumbiehl <florz@florz.de> Acked-by: Michal Ostrowski <mostrows@earthlink.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/pppoe.c19
1 files changed, 6 insertions, 13 deletions
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index f761a9aae4c..bc4fc30bc85 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -218,17 +218,6 @@ static inline struct pppox_sock *get_item_by_addr(struct sockaddr_pppox *sp)
return get_item(sp->sa_addr.pppoe.sid, sp->sa_addr.pppoe.remote, ifindex);
}
-static inline int set_item(struct pppox_sock *po)
-{
- int i;
-
- write_lock_bh(&pppoe_hash_lock);
- i = __set_item(po);
- write_unlock_bh(&pppoe_hash_lock);
-
- return i;
-}
-
static inline struct pppox_sock *delete_item(unsigned long sid, char *addr, int ifindex)
{
struct pppox_sock *ret;
@@ -595,14 +584,18 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
po->pppoe_dev = dev;
po->pppoe_ifindex = dev->ifindex;
- if (!(dev->flags & IFF_UP))
+ write_lock_bh(&pppoe_hash_lock);
+ if (!(dev->flags & IFF_UP)){
+ write_unlock_bh(&pppoe_hash_lock);
goto err_put;
+ }
memcpy(&po->pppoe_pa,
&sp->sa_addr.pppoe,
sizeof(struct pppoe_addr));
- error = set_item(po);
+ error = __set_item(po);
+ write_unlock_bh(&pppoe_hash_lock);
if (error < 0)
goto err_put;