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.

> 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 *
> 

Reply via email to