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