udp: pcb list/hashtable protection stage 2/2
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Thu, 23 Dec 2010 08:03:08 +0000 (16:03 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Mon, 31 Jan 2011 01:46:06 +0000 (09:46 +0800)
- Use serializer to protect pcb list/hashtable iteration not running
  in netisrs.
- Don't use marker pcb, so except for the functions running in netisr0,
  no other functions will alter pcb list.

sys/netinet/in.c
sys/netinet/udp_usrreq.c
sys/netinet/udp_var.h
sys/netinet6/in6_ifattach.c
sys/netinet6/udp6_usrreq.c

index 5e886e4..c69cfaf 100644 (file)
@@ -58,6 +58,7 @@
 #include <netinet/in.h>
 #include <netinet/in_var.h>
 #include <netinet/in_pcb.h>
+#include <netinet/udp_var.h>
 
 #include <netinet/igmp_var.h>
 
@@ -88,7 +89,6 @@ SYSCTL_INT(_net_inet_ip, OID_AUTO, subnets_are_local, CTLFLAG_RW,
 struct in_multihead in_multihead; /* XXX BSS initialization */
 
 extern struct inpcbinfo ripcbinfo;
-extern struct inpcbinfo udbinfo;
 
 /*
  * Return 1 if an internet address is for a ``local'' host
@@ -1389,5 +1389,8 @@ void
 in_ifdetach(struct ifnet *ifp)
 {
        in_pcbpurgeif0(LIST_FIRST(&ripcbinfo.pcblisthead), ifp);
+
+       udbinfo_lock();
        in_pcbpurgeif0(LIST_FIRST(&udbinfo.pcblisthead), ifp);
+       udbinfo_unlock();
 }
index b4b58e2..b240bdb 100644 (file)
@@ -88,6 +88,7 @@
 
 #include <sys/thread2.h>
 #include <sys/socketvar2.h>
+#include <sys/serialize.h>
 
 #include <machine/stdarg.h>
 
@@ -147,6 +148,7 @@ SYSCTL_INT(_net_inet_udp, OID_AUTO, strict_mcast_mship, CTLFLAG_RW,
 struct inpcbinfo udbinfo;
 
 static struct netisr_barrier *udbinfo_br;
+static struct lwkt_serialize udbinfo_slize = LWKT_SERIALIZE_INITIALIZER;
 
 #ifndef UDBHASHSIZE
 #define UDBHASHSIZE 16
@@ -357,8 +359,7 @@ udp_input(struct mbuf **mp, int *offp, int proto)
                udp_in6.uin6_init_done = udp_ip6.uip6_init_done = 0;
 #endif
                LIST_FOREACH(inp, &udbinfo.pcblisthead, inp_list) {
-                       if (inp->inp_flags & INP_PLACEMARKER)
-                               continue;
+                       KKASSERT((inp->inp_flags & INP_PLACEMARKER) == 0);
 #ifdef INET6
                        if (!(inp->inp_vflag & INP_IPV4))
                                continue;
@@ -715,8 +716,19 @@ done:
        lwkt_replymsg(&msg->lmsg, 0);
 }
 
+static int
+udp_pcblist(SYSCTL_HANDLER_ARGS)
+{
+       int error;
+
+       udbinfo_lock();
+       error = in_pcblist_global_nomarker(oidp, arg1, arg2, req);
+       udbinfo_unlock();
+
+       return error;
+}
 SYSCTL_PROC(_net_inet_udp, UDPCTL_PCBLIST, pcblist, CTLFLAG_RD, &udbinfo, 0,
-           in_pcblist_global, "S,xinpcb", "List of active UDP sockets");
+           udp_pcblist, "S,xinpcb", "List of active UDP sockets");
 
 static int
 udp_getcred(SYSCTL_HANDLER_ARGS)
@@ -731,6 +743,8 @@ udp_getcred(SYSCTL_HANDLER_ARGS)
        error = SYSCTL_IN(req, addrs, sizeof addrs);
        if (error)
                return (error);
+
+       udbinfo_lock();
        inp = in_pcblookup_hash(&udbinfo, addrs[1].sin_addr, addrs[1].sin_port,
                                addrs[0].sin_addr, addrs[0].sin_port, 1, NULL);
        if (inp == NULL || inp->inp_socket == NULL) {
@@ -739,6 +753,7 @@ udp_getcred(SYSCTL_HANDLER_ARGS)
        }
        error = SYSCTL_OUT(req, inp->inp_socket->so_cred, sizeof(struct ucred));
 out:
+       udbinfo_unlock();
        return (error);
 }
 
@@ -1240,15 +1255,29 @@ udp_shutdown(netmsg_t msg)
        lwkt_replymsg(&msg->shutdown.base.lmsg, error);
 }
 
+void
+udbinfo_lock(void)
+{
+       lwkt_serialize_enter(&udbinfo_slize);
+}
+
+void
+udbinfo_unlock(void)
+{
+       lwkt_serialize_exit(&udbinfo_slize);
+}
+
 static void
 udbinfo_barrier_set(void)
 {
        netisr_barrier_set(udbinfo_br);
+       udbinfo_lock();
 }
 
 static void
 udbinfo_barrier_rem(void)
 {
+       udbinfo_unlock();
        netisr_barrier_rem(udbinfo_br);
 }
 
index ef41eb6..513c6ba 100644 (file)
@@ -158,6 +158,9 @@ void                        udp_shutdown (union netmsg *);
 struct lwkt_port       *udp_ctlport (int, struct sockaddr *, void *);
 struct lwkt_port       *udp_cport (int);
 
+void                   udbinfo_lock(void);
+void                   udbinfo_unlock(void);
+
 #endif
 
 #endif
index b9759cd..378baf8 100644 (file)
@@ -50,6 +50,7 @@
 #include <netinet/in_var.h>
 #include <netinet/if_ether.h>
 #include <netinet/in_pcb.h>
+#include <netinet/udp_var.h>
 
 #include <netinet/ip6.h>
 #include <netinet6/ip6_var.h>
@@ -72,7 +73,6 @@ int ip6_auto_linklocal = 1;   /* enable by default */
 
 struct callout in6_tmpaddrtimer_ch;
 
-extern struct inpcbinfo udbinfo;
 extern struct inpcbinfo ripcbinfo;
 
 static int get_rand_ifid (struct ifnet *, struct in6_addr *);
@@ -846,7 +846,10 @@ in6_ifdetach(struct ifnet *ifp)
        }
 
        /* leave from all multicast groups joined */
+       udbinfo_lock();
        in6_pcbpurgeif0(LIST_FIRST(&udbinfo.pcblisthead), ifp);
+       udbinfo_unlock();
+
        in6_pcbpurgeif0(LIST_FIRST(&ripcbinfo.pcblisthead), ifp);
        for (in6m = LIST_FIRST(&in6_multihead); in6m; in6m = in6m_next) {
                in6m_next = LIST_NEXT(in6m, in6m_entry);
index 30657fa..1c4e837 100644 (file)
@@ -234,8 +234,8 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
                 */
                last = NULL;
                LIST_FOREACH(in6p, &udbinfo.pcblisthead, inp_list) {
-                       if (in6p->inp_flags & INP_PLACEMARKER)
-                               continue;
+                       KKASSERT((in6p->inp_flags & INP_PLACEMARKER) == 0);
+
                        if (!(in6p->inp_vflag & INP_IPV6))
                                continue;
                        if (in6p->in6p_lport != uh->uh_dport)