> Date: Mon, 15 Aug 2016 22:08:16 +1000
> From: Jonathan Matthew <[email protected]>
> 
> This removes ART's reliance on the kernel lock to serialise updates.
> I sent out an earlier version of this prior to 6.0, but it didn't make it in.
> Since then, we've decided to go with rwlocks in the packet processing path,
> so here's a version with an rwlock instead of a mutex.

Merely out of curiousity: is there any reason to only use write locks
here?  Naively you'd think this would be a case where making use of
the multiple-reader, single-writer property of rwlocks would make
sense...

> Index: art.c
> ===================================================================
> RCS file: /cvs/src/sys/net/art.c,v
> retrieving revision 1.22
> diff -u -p -r1.22 art.c
> --- art.c     19 Jul 2016 10:51:44 -0000      1.22
> +++ art.c     14 Aug 2016 11:10:45 -0000
> @@ -152,6 +152,7 @@ art_alloc(unsigned int rtableid, unsigne
>  
>       ar->ar_off = off;
>       ar->ar_rtableid = rtableid;
> +     rw_init(&ar->ar_lock, "art");
>  
>       return (ar);
>  }
> @@ -378,7 +379,7 @@ art_insert(struct art_root *ar, struct a
>       struct art_node         *node;
>       int                      i, j;
>  
> -     KERNEL_ASSERT_LOCKED();
> +     rw_assert_wrlock(&ar->ar_lock);
>       KASSERT(plen >= 0 && plen <= ar->ar_alen);
>  
>       at = srp_get_locked(&ar->ar_root);
> @@ -482,7 +483,7 @@ art_delete(struct art_root *ar, struct a
>       struct art_node         *node;
>       int                      i, j;
>  
> -     KERNEL_ASSERT_LOCKED();
> +     rw_assert_wrlock(&ar->ar_lock);
>       KASSERT(plen >= 0 && plen <= ar->ar_alen);
>  
>       at = srp_get_locked(&ar->ar_root);
> @@ -613,7 +614,7 @@ art_walk(struct art_root *ar, int (*f)(s
>       struct art_node         *node;
>       int                      error = 0;
>  
> -     KERNEL_LOCK();
> +     rw_enter_write(&ar->ar_lock);
>       at = srp_get_locked(&ar->ar_root);
>       if (at != NULL) {
>               art_table_ref(ar, at);
> @@ -631,7 +632,7 @@ art_walk(struct art_root *ar, int (*f)(s
>  
>               art_table_free(ar, at);
>       }
> -     KERNEL_UNLOCK();
> +     rw_exit_write(&ar->ar_lock);
>  
>       return (error);
>  }
> @@ -708,9 +709,9 @@ art_walk_apply(struct art_root *ar,
>  
>       if ((an != NULL) && (an != next)) {
>               /* this assumes an->an_dst is not used by f */
> -             KERNEL_UNLOCK();
> +             rw_exit_write(&ar->ar_lock);
>               error = (*f)(an, arg);
> -             KERNEL_LOCK();
> +             rw_enter_write(&ar->ar_lock);
>       }
>  
>       return (error);
> Index: art.h
> ===================================================================
> RCS file: /cvs/src/sys/net/art.h,v
> retrieving revision 1.14
> diff -u -p -r1.14 art.h
> --- art.h     14 Jun 2016 04:42:02 -0000      1.14
> +++ art.h     14 Aug 2016 11:10:45 -0000
> @@ -19,6 +19,8 @@
>  #ifndef _NET_ART_H_
>  #define _NET_ART_H_
>  
> +#include <sys/rwlock.h>
> +
>  #define ART_MAXLVL   32      /* We currently use 32 levels for IPv6. */
>  
>  /*
> @@ -26,6 +28,7 @@
>   */
>  struct art_root {
>       struct srp               ar_root;       /* First table */
> +     struct rwlock            ar_lock;       /* Serialise modifications */
>       uint8_t                  ar_bits[ART_MAXLVL];   /* Per level stride */
>       uint8_t                  ar_nlvl;       /* Number of levels */
>       uint8_t                  ar_alen;       /* Address length in bits */
> Index: rtable.c
> ===================================================================
> RCS file: /cvs/src/sys/net/rtable.c,v
> retrieving revision 1.50
> diff -u -p -r1.50 rtable.c
> --- rtable.c  19 Jul 2016 10:51:44 -0000      1.50
> +++ rtable.c  14 Aug 2016 11:10:45 -0000
> @@ -515,6 +515,10 @@ static inline uint8_t    *satoaddr(struct a
>  void rtentry_ref(void *, void *);
>  void rtentry_unref(void *, void *);
>  
> +#ifndef SMALL_KERNEL
> +void rtable_mpath_insert(struct art_node *, struct rtentry *);
> +#endif
> +
>  struct srpl_rc rt_rc = SRPL_RC_INITIALIZER(rtentry_ref, rtentry_unref, NULL);
>  
>  void
> @@ -679,8 +683,6 @@ rtable_insert(unsigned int rtableid, str
>       unsigned int                     rt_flags;
>       int                              error = 0;
>  
> -     KERNEL_ASSERT_LOCKED();
> -
>       ar = rtable_get(rtableid, dst->sa_family);
>       if (ar == NULL)
>               return (EAFNOSUPPORT);
> @@ -691,6 +693,7 @@ rtable_insert(unsigned int rtableid, str
>               return (EINVAL);
>  
>       rtref(rt); /* guarantee rtfree won't do anything during insert */
> +     rw_enter_write(&ar->ar_lock);
>  
>  #ifndef SMALL_KERNEL
>       /* Do not permit exactly the same dst/mask/gw pair. */
> @@ -766,15 +769,14 @@ rtable_insert(unsigned int rtableid, str
>                       }
>               }
>  
> -             SRPL_INSERT_HEAD_LOCKED(&rt_rc, &an->an_rtlist, rt, rt_next);
> -
>               /* Put newly inserted entry at the right place. */
> -             rtable_mpath_reprio(rtableid, dst, mask, rt->rt_priority, rt);
> +             rtable_mpath_insert(an, rt);
>  #else
>               error = EEXIST;
>  #endif /* SMALL_KERNEL */
>       }
>  leave:
> +     rw_exit_write(&ar->ar_lock);
>       rtfree(rt);
>       return (error);
>  }
> @@ -792,6 +794,7 @@ rtable_delete(unsigned int rtableid, str
>       struct rtentry                  *mrt;
>       int                              npaths = 0;
>  #endif /* SMALL_KERNEL */
> +     int                              error = 0;
>  
>       ar = rtable_get(rtableid, dst->sa_family);
>       if (ar == NULL)
> @@ -800,15 +803,17 @@ rtable_delete(unsigned int rtableid, str
>       addr = satoaddr(ar, dst);
>       plen = rtable_satoplen(dst->sa_family, mask);
>  
> -     KERNEL_ASSERT_LOCKED();
> -
> +     rtref(rt); /* guarantee rtfree won't do anything under ar_lock */
> +     rw_enter_write(&ar->ar_lock);
>       an = art_lookup(ar, addr, plen, &sr);
>       srp_leave(&sr); /* an can't go away while we have the lock */
>  
>       /* Make sure we've got a perfect match. */
>       if (an == NULL || an->an_plen != plen ||
> -         memcmp(an->an_dst, dst, dst->sa_len))
> -             return (ESRCH);
> +         memcmp(an->an_dst, dst, dst->sa_len)) {
> +             error = ESRCH;
> +             goto leave;
> +     }
>  
>  #ifndef SMALL_KERNEL
>       /*
> @@ -827,18 +832,23 @@ rtable_delete(unsigned int rtableid, str
>               an->an_dst = mrt->rt_dest;
>               if (npaths == 2)
>                       mrt->rt_flags &= ~RTF_MPATH;
> -             return (0);
> +
> +             goto leave;
>       }
>  #endif /* SMALL_KERNEL */
>  
>       if (art_delete(ar, an, addr, plen) == NULL)
> -             return (ESRCH);
> +             panic("art_delete failed to find node %p", an);
>  
>       KASSERT(rt->rt_refcnt >= 1);
>       SRPL_REMOVE_LOCKED(&rt_rc, &an->an_rtlist, rt, rtentry, rt_next);
> -
>       art_put(an);
> -     return (0);
> +
> +leave:
> +     rw_exit_write(&ar->ar_lock);
> +     rtfree(rt);
> +
> +     return (error);
>  }
>  
>  struct rtable_walk_cookie {
> @@ -905,7 +915,7 @@ rtable_mpath_reprio(unsigned int rtablei
>       struct srp_ref                   sr;
>       uint8_t                         *addr;
>       int                              plen;
> -     struct rtentry                  *mrt, *prt = NULL;
> +     int                              error = 0;
>  
>       ar = rtable_get(rtableid, dst->sa_family);
>       if (ar == NULL)
> @@ -914,19 +924,32 @@ rtable_mpath_reprio(unsigned int rtablei
>       addr = satoaddr(ar, dst);
>       plen = rtable_satoplen(dst->sa_family, mask);
>  
> -     KERNEL_ASSERT_LOCKED();
> -
> +     rw_enter_write(&ar->ar_lock);
>       an = art_lookup(ar, addr, plen, &sr);
>       srp_leave(&sr); /* an can't go away while we have the lock */
>  
>       /* Make sure we've got a perfect match. */
>       if (an == NULL || an->an_plen != plen ||
>           memcmp(an->an_dst, dst, dst->sa_len))
> -             return (ESRCH);
> +             error = ESRCH;
> +     else {
> +             rtref(rt); /* keep rt alive in between remove and insert */
> +             SRPL_REMOVE_LOCKED(&rt_rc, &an->an_rtlist,
> +                 rt, rtentry, rt_next);
> +             rt->rt_priority = prio;
> +             rtable_mpath_insert(an, rt);
> +             rtfree(rt);
> +     }
> +     rw_exit_write(&ar->ar_lock);
>  
> -     rtref(rt); /* keep rt alive in between remove and add */
> -     SRPL_REMOVE_LOCKED(&rt_rc, &an->an_rtlist, rt, rtentry, rt_next);
> -     rt->rt_priority = prio;
> +     return (error);
> +}
> +
> +void
> +rtable_mpath_insert(struct art_node *an, struct rtentry *rt)
> +{
> +     struct rtentry                  *mrt, *prt = NULL;
> +     uint8_t                          prio = rt->rt_priority;
>  
>       if ((mrt = SRPL_FIRST_LOCKED(&an->an_rtlist)) != NULL) {
>               /*
> @@ -957,9 +980,6 @@ rtable_mpath_reprio(unsigned int rtablei
>       } else {
>               SRPL_INSERT_HEAD_LOCKED(&rt_rc, &an->an_rtlist, rt, rt_next);
>       }
> -     rtfree(rt);
> -
> -     return (0);
>  }
>  
>  struct rtentry *
> 
> 

Reply via email to