On Mon, Dec 11, 2017 at 08:10:47AM +0100, Martin Pieuchot wrote:
> On 29/11/17(Wed) 20:28, Claudio Jeker wrote:
> > This diff changes the the PCB list into an SRP list. Therefor concurrent
> > access is no longer an issue and route_input() could be more unlocked.
> > There is not much point of releasing the KERNEL_LOCK for now but I added
> > commented lock / unlock to the code.
> >
> > Next on the list are now the socekt functions sorwakeup, sbspace and
> > sbappendaddr. If those are save then route_input should be save.
> >
> > If this is the way to go then doing the same for pfkey should be straight
> > forward.
> >
> > Looking forward to test reports and comments
>
> rw_enter() will not wail so its returned value don't need to be checked.
>
> I'm not fan of the commented KERNEL_LOCK/UNLOCK dance, but either way I
> think this should go in.
I'm happy to remove them before commit.
> > Index: net/rtsock.c
> > ===================================================================
> > RCS file: /cvs/src/sys/net/rtsock.c,v
> > retrieving revision 1.255
> > diff -u -p -r1.255 rtsock.c
> > --- net/rtsock.c 3 Nov 2017 16:23:20 -0000 1.255
> > +++ net/rtsock.c 29 Nov 2017 18:54:26 -0000
> > @@ -70,6 +70,7 @@
> > #include <sys/socketvar.h>
> > #include <sys/domain.h>
> > #include <sys/protosw.h>
> > +#include <sys/srp.h>
> >
> > #include <net/if.h>
> > #include <net/if_dl.h>
> > @@ -94,7 +95,6 @@
> > #include <sys/kernel.h>
> > #include <sys/timeout.h>
> >
> > -struct sockaddr route_dst = { 2, PF_ROUTE, };
> > struct sockaddr route_src = { 2, PF_ROUTE, };
> >
> > struct walkarg {
> > @@ -103,6 +103,8 @@ struct walkarg {
> > };
> >
> > void route_prinit(void);
> > +void route_ref(void *, void *);
> > +void route_unref(void *, void *);
> > int route_output(struct mbuf *, struct socket *, struct sockaddr *,
> > struct mbuf *);
> > int route_ctloutput(int, struct socket *, int, int, struct mbuf *);
> > @@ -133,7 +135,8 @@ int sysctl_rtable_rtstat(void *, size_
> >
> > struct routecb {
> > struct rawcb rcb;
> > - LIST_ENTRY(routecb) rcb_list;
> > + SRPL_ENTRY(routecb) rcb_list;
> > + struct refcnt refcnt;
> > struct timeout timeout;
> > unsigned int msgfilter;
> > unsigned int flags;
> > @@ -142,11 +145,10 @@ struct routecb {
> > #define sotoroutecb(so) ((struct routecb *)(so)->so_pcb)
> >
> > struct route_cb {
> > - LIST_HEAD(, routecb) rcb;
> > - int ip_count;
> > - int ip6_count;
> > - int mpls_count;
> > - int any_count;
> > + SRPL_HEAD(, routecb) rcb;
> > + struct srpl_rc rcb_rc;
> > + struct rwlock rcb_lk;
> > + unsigned int any_count;
> > };
> >
> > struct route_cb route_cb;
> > @@ -165,9 +167,26 @@ struct route_cb route_cb;
> > void
> > route_prinit(void)
> > {
> > - LIST_INIT(&route_cb.rcb);
> > + srpl_rc_init(&route_cb.rcb_rc, route_ref, route_unref, NULL);
> > + rw_init(&route_cb.rcb_lk, "rtsock");
> > + SRPL_INIT(&route_cb.rcb);
> > }
> >
> > +void
> > +route_ref(void *null, void *v)
> > +{
> > + struct routecb *rop = v;
> > +
> > + refcnt_take(&rop->refcnt);
> > +}
> > +
> > +void
> > +route_unref(void *null, void *v)
> > +{
> > + struct routecb *rop = v;
> > +
> > + refcnt_rele_wake(&rop->refcnt);
> > +}
> >
> > int
> > route_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
> > @@ -218,9 +237,10 @@ route_attach(struct socket *so, int prot
> > */
> > rop = malloc(sizeof(struct routecb), M_PCB, M_WAITOK|M_ZERO);
> > rp = &rop->rcb;
> > - so->so_pcb = rp;
> > + so->so_pcb = rop;
> > /* Init the timeout structure */
> > - timeout_set(&rop->timeout, route_senddesync, rp);
> > + timeout_set(&rop->timeout, route_senddesync, rop);
> > + refcnt_init(&rop->refcnt);
> >
> > if (curproc == NULL)
> > error = EACCES;
> > @@ -230,31 +250,33 @@ route_attach(struct socket *so, int prot
> > free(rop, M_PCB, sizeof(struct routecb));
> > return (error);
> > }
> > +
> > rp->rcb_socket = so;
> > rp->rcb_proto.sp_family = so->so_proto->pr_domain->dom_family;
> > rp->rcb_proto.sp_protocol = proto;
> >
> > rop->rtableid = curproc->p_p->ps_rtableid;
> > - switch (rp->rcb_proto.sp_protocol) {
> > - case AF_INET:
> > - route_cb.ip_count++;
> > - break;
> > - case AF_INET6:
> > - route_cb.ip6_count++;
> > - break;
> > -#ifdef MPLS
> > - case AF_MPLS:
> > - route_cb.mpls_count++;
> > - break;
> > -#endif
> > - }
> >
> > soisconnected(so);
> > so->so_options |= SO_USELOOPBACK;
> >
> > + /* KERNEL_UNLOCK(); */
> > +
> > rp->rcb_faddr = &route_src;
> > +
> > + error = rw_enter(&route_cb.rcb_lk, RW_WRITE);
> > + if (error != 0) {
> > + free(rop, M_PCB, sizeof(struct routecb));
> > + /* KERNEL_LOCK(); */
> > + return (error);
> > + }
> > +
> > + SRPL_INSERT_HEAD_LOCKED(&route_cb.rcb_rc, &route_cb.rcb, rop, rcb_list);
> > route_cb.any_count++;
> > - LIST_INSERT_HEAD(&route_cb.rcb, rop, rcb_list);
> > +
> > + rw_exit(&route_cb.rcb_lk);
> > +
> > + /* KERNEL_LOCK(); */
> >
> > return (0);
> > }
> > @@ -263,7 +285,7 @@ int
> > route_detach(struct socket *so)
> > {
> > struct routecb *rop;
> > - int af;
> > + int error;
> >
> > soassertlocked(so);
> >
> > @@ -271,18 +293,24 @@ route_detach(struct socket *so)
> > if (rop == NULL)
> > return (EINVAL);
> >
> > + /* KERNEL_UNLOCK(); */
> > +
> > + error = rw_enter(&route_cb.rcb_lk, RW_WRITE);
> > + if (error != 0) {
> > + /* KERNEL_LOCK(); */
> > + return (error);
> > + }
> > +
> > timeout_del(&rop->timeout);
> > - af = rop->rcb.rcb_proto.sp_protocol;
> > - if (af == AF_INET)
> > - route_cb.ip_count--;
> > - else if (af == AF_INET6)
> > - route_cb.ip6_count--;
> > -#ifdef MPLS
> > - else if (af == AF_MPLS)
> > - route_cb.mpls_count--;
> > -#endif
> > route_cb.any_count--;
> > - LIST_REMOVE(rop, rcb_list);
> > +
> > + SRPL_REMOVE_LOCKED(&route_cb.rcb_rc, &route_cb.rcb,
> > + rop, routecb, rcb_list);
> > +
> > + rw_exit(&route_cb.rcb_lk);
> > + /* wait for all references to drop */
> > + refcnt_finalize(&rop->refcnt, "rtsockrefs");
> > + /* KERNEL_LOCK(); */
> >
> > so->so_pcb = NULL;
> > sofree(so);
> > @@ -348,12 +376,10 @@ route_ctloutput(int op, struct socket *s
> > void
> > route_senddesync(void *data)
> > {
> > - struct rawcb *rp;
> > struct routecb *rop;
> > struct mbuf *desync_mbuf;
> >
> > - rp = (struct rawcb *)data;
> > - rop = (struct routecb *)rp;
> > + rop = (struct routecb *)data;
> >
> > /* If we are in a DESYNC state, try to send a RTM_DESYNC packet */
> > if ((rop->flags & ROUTECB_FLAG_DESYNC) == 0)
> > @@ -365,11 +391,11 @@ route_senddesync(void *data)
> > */
> > desync_mbuf = rtm_msg1(RTM_DESYNC, NULL);
> > if (desync_mbuf != NULL) {
> > - struct socket *so = rp->rcb_socket;
> > + struct socket *so = rop->rcb.rcb_socket;
> > if (sbappendaddr(so, &so->so_rcv, &route_src,
> > desync_mbuf, NULL) != 0) {
> > rop->flags &= ~ROUTECB_FLAG_DESYNC;
> > - sorwakeup(rp->rcb_socket);
> > + sorwakeup(rop->rcb.rcb_socket);
> > return;
> > }
> > m_freem(desync_mbuf);
> > @@ -381,26 +407,22 @@ route_senddesync(void *data)
> > void
> > route_input(struct mbuf *m0, struct socket *so, sa_family_t sa_family)
> > {
> > - struct rawcb *rp;
> > struct routecb *rop;
> > + struct rawcb *rp;
> > struct rt_msghdr *rtm;
> > struct mbuf *m = m0;
> > - int sockets = 0;
> > struct socket *last = NULL;
> > - struct sockaddr *sosrc, *sodst;
> > + struct srp_ref sr;
> >
> > KERNEL_ASSERT_LOCKED();
> >
> > - sosrc = &route_src;
> > - sodst = &route_dst;
> > -
> > /* ensure that we can access the rtm_type via mtod() */
> > if (m->m_len < offsetof(struct rt_msghdr, rtm_type) + 1) {
> > m_freem(m);
> > return;
> > }
> >
> > - LIST_FOREACH(rop, &route_cb.rcb, rcb_list) {
> > + SRPL_FOREACH(rop, &sr, &route_cb.rcb, rcb_list) {
> > rp = &rop->rcb;
> > if (!(rp->rcb_socket->so_state & SS_ISCONNECTED))
> > continue;
> > @@ -459,8 +481,8 @@ route_input(struct mbuf *m0, struct sock
> > struct mbuf *n;
> > if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) != NULL) {
> > if (sbspace(last, &last->so_rcv) < (2*MSIZE) ||
> > - sbappendaddr(last, &last->so_rcv, sosrc,
> > - n, (struct mbuf *)NULL) == 0) {
> > + sbappendaddr(last, &last->so_rcv,
> > + &route_src, n, (struct mbuf *)NULL) == 0) {
> > /*
> > * Flag socket as desync'ed and
> > * flush required
> > @@ -468,31 +490,35 @@ route_input(struct mbuf *m0, struct sock
> > sotoroutecb(last)->flags |=
> > ROUTECB_FLAG_DESYNC |
> > ROUTECB_FLAG_FLUSH;
> > - route_senddesync(sotorawcb(last));
> > + route_senddesync(sotoroutecb(last));
> > m_freem(n);
> > } else {
> > sorwakeup(last);
> > - sockets++;
> > }
> > }
> > + refcnt_rele_wake(&sotoroutecb(last)->refcnt);
> > }
> > - last = rp->rcb_socket;
> > + /* keep a reference for last */
> > + refcnt_take(&rop->refcnt);
> > + last = rop->rcb.rcb_socket;
> > }
> > if (last) {
> > if (sbspace(last, &last->so_rcv) < (2 * MSIZE) ||
> > - sbappendaddr(last, &last->so_rcv, sosrc,
> > + sbappendaddr(last, &last->so_rcv, &route_src,
> > m, (struct mbuf *)NULL) == 0) {
> > /* Flag socket as desync'ed and flush required */
> > sotoroutecb(last)->flags |=
> > ROUTECB_FLAG_DESYNC | ROUTECB_FLAG_FLUSH;
> > - route_senddesync(sotorawcb(last));
> > + route_senddesync(sotoroutecb(last));
> > m_freem(m);
> > } else {
> > sorwakeup(last);
> > - sockets++;
> > }
> > + refcnt_rele_wake(&sotoroutecb(last)->refcnt);
> > } else
> > m_freem(m);
> > +
> > + SRPL_LEAVE(&sr);
> > }
> >
> > struct rt_msghdr *
> >
>
--
:wq Claudio