Index: art.c =================================================================== RCS file: /cvs/src/sys/net/art.c,v retrieving revision 1.18 diff -u -p -r1.18 art.c --- art.c 3 Jun 2016 03:59:43 -0000 1.18 +++ art.c 3 Jun 2016 10:36:34 -0000 @@ -1,4 +1,4 @@ -/* $OpenBSD: art.c,v 1.18 2016/06/03 03:59:43 dlg Exp $ */ +/* $OpenBSD: art.c,v 1.14 2016/04/13 08:04:14 mpi Exp $ */ /* * Copyright (c) 2015 Martin Pieuchot @@ -37,8 +37,8 @@ #include -#define ISLEAF(e) (((unsigned long)(e).node & 1) == 0) -#define SUBTABLE(e) (((struct art_table *)((unsigned long)(e).child & ~1))) +#define ISLEAF(e) (((unsigned long)(e) & 1) == 0) +#define SUBTABLE(e) ((struct art_table *)((unsigned long)(e) & ~1)) #define ASNODE(t) ((struct art_node *)((unsigned long)(t) | 1)) /* @@ -58,8 +58,7 @@ struct art_table { * is a route counter. */ union { - struct art_node *node; - struct art_table *child; + struct srp node; unsigned long count; } *at_heap; /* Array of 2^(slen+1) items */ }; @@ -249,41 +248,62 @@ art_findex(struct art_table *at, uint8_t * Return the best existing match for a destination. */ struct art_node * -art_match(struct art_root *ar, uint8_t *addr) +art_match(struct art_root *ar, uint8_t *addr, struct srp_ref *nsr) { + struct srp_ref noder, dfltr, ndfltr; + void *entry; struct art_table *at; - struct art_node *dflt = NULL; - int j; + struct art_node *dflt, *node; + int j; + + entry = srp_enter(&noder, &ar->ar_root); + at = entry; - at = ar->ar_root; if (at == NULL) - return (NULL); + goto done; + + node = srp_enter(&dfltr, &at->at_default); + dflt = node; /* * Iterate until we find a leaf. */ while (1) { - /* - * Rember the default route of this table in case - * we do not find a better matching route. - */ - if (at->at_default != NULL) - dflt = at->at_default; - /* Do a single level route lookup. */ j = art_findex(at, addr); + entry = srp_follow(&noder, &at->at_heap[j].node); /* If this is a leaf we're done. */ - if (ISLEAF(at->at_heap[j])) + if (ISLEAF(entry)) break; - at = SUBTABLE(at->at_heap[j]); + at = SUBTABLE(entry); + + /* + * Remember the default route of this table in case + * we do not find a better matching route. + */ + node = srp_enter(&ndfltr, &at->at_default); + if (node != NULL) { + srp_leave(&dfltr); + dfltr = ndfltr; + dflt = node; + } else + srp_leave(&ndfltr); } - if (at->at_heap[j].node != NULL) - return (at->at_heap[j].node); + if (entry == NULL) { + srp_leave(&noder); + *nsr = dfltr; + KASSERT(ISLEAF(dflt)); + return (dflt); + } - return (dflt); + srp_leave(&dfltr); +done: + *nsr = noder; + KASSERT(ISLEAF(entry)); + return (entry); } /* @@ -293,21 +313,25 @@ art_match(struct art_root *ar, uint8_t * * it does not exist. */ struct art_node * -art_lookup(struct art_root *ar, uint8_t *addr, int plen) +art_lookup(struct art_root *ar, uint8_t *addr, int plen, struct srp_ref *nsr) { + void *entry; struct art_table *at; - struct art_node *an; int i, j; KASSERT(plen >= 0 && plen <= ar->ar_alen); - at = ar->ar_root; + entry = srp_enter(nsr, &ar->ar_root); + at = entry; + if (at == NULL) - return (NULL); + goto done; /* Default route */ - if (plen == 0) - return (at->at_default); + if (plen == 0) { + entry = srp_follow(nsr, &at->at_default); + goto done; + } /* * If the prefix length is smaller than the sum of @@ -317,24 +341,26 @@ art_lookup(struct art_root *ar, uint8_t while (plen > (at->at_offset + at->at_bits)) { /* Do a single level route lookup. */ j = art_findex(at, addr); + entry = srp_follow(nsr, &at->at_heap[j].node); /* A leaf is a match, but not a perfect one. */ - if (ISLEAF(at->at_heap[j])) + if (ISLEAF(entry)) return (NULL); - at = SUBTABLE(at->at_heap[j]); + at = SUBTABLE(entry); } i = art_bindex(at, addr, plen); if (i == -1) return (NULL); - if (!ISLEAF(at->at_heap[i])) - an = SUBTABLE(at->at_heap[i])->at_default; - else - an = at->at_heap[i].node; - - return (an); + entry = srp_follow(nsr, &at->at_heap[i].node); + if (!ISLEAF(entry)) + entry = srp_follow(nsr, &SUBTABLE(entry)->at_default); + +done: + KASSERT(ISLEAF(entry)); + return (entry); } @@ -347,27 +373,30 @@ art_lookup(struct art_root *ar, uint8_t struct art_node * art_insert(struct art_root *ar, struct art_node *an, uint8_t *addr, int plen) { - struct art_table *at; + struct art_table *at, *child; + struct art_node *node; int i, j; + KERNEL_ASSERT_LOCKED(); KASSERT(plen >= 0 && plen <= ar->ar_alen); - at = ar->ar_root; + at = srp_get_locked(&ar->ar_root); if (at == NULL) { at = art_table_get(ar, NULL, -1); if (at == NULL) return (NULL); - ar->ar_root = at; + srp_swap_locked(&ar->ar_root, at); } /* Default route */ if (plen == 0) { - if (at->at_default != NULL) - return (at->at_default); + node = srp_get_locked(&at->at_default); + if (node != NULL) + return (node); art_table_ref(ar, at); - at->at_default = an; + srp_swap_locked(&at->at_default, an); return (an); } @@ -379,6 +408,7 @@ art_insert(struct art_root *ar, struct a while (plen > (at->at_offset + at->at_bits)) { /* Do a single level route lookup. */ j = art_findex(at, addr); + node = srp_get_locked(&at->at_heap[j].node); /* * If the node corresponding to the fringe index is @@ -386,18 +416,16 @@ art_insert(struct art_root *ar, struct a * entry of this node will then become the default * route of the subtable. */ - if (ISLEAF(at->at_heap[j])) { - struct art_table *child; - + if (ISLEAF(node)) { child = art_table_get(ar, at, j); if (child == NULL) return (NULL); art_table_ref(ar, at); - at->at_heap[j].node = ASNODE(child); - } - - at = SUBTABLE(at->at_heap[j]); + srp_swap_locked(&at->at_heap[j].node, ASNODE(child)); + at = child; + } else + at = SUBTABLE(node); } i = art_bindex(at, addr, plen); @@ -414,12 +442,13 @@ struct art_node * art_table_insert(struct art_root *ar, struct art_table *at, int i, struct art_node *an) { - struct art_node *prev; + struct art_node *prev, *node; - if (!ISLEAF(at->at_heap[i])) - prev = SUBTABLE(at->at_heap[i])->at_default; + node = srp_get_locked(&at->at_heap[i].node); + if (!ISLEAF(node)) + prev = srp_get_locked(&SUBTABLE(node)->at_default); else - prev = at->at_heap[i].node; + prev = node; if (art_check_duplicate(ar, prev, an)) return (prev); @@ -433,10 +462,10 @@ art_table_insert(struct art_root *ar, st */ if (i < at->at_minfringe) art_allot(at, i, prev, an); - else if (!ISLEAF(at->at_heap[i])) - SUBTABLE(at->at_heap[i])->at_default = an; + else if (!ISLEAF(node)) + srp_swap_locked(&SUBTABLE(node)->at_default, an); else - at->at_heap[i].node = an; + srp_swap_locked(&at->at_heap[i].node, an); return (an); } @@ -449,21 +478,22 @@ struct art_node * art_delete(struct art_root *ar, struct art_node *an, uint8_t *addr, int plen) { struct art_table *at; - struct art_node *dflt; + struct art_node *node; int i, j; + KERNEL_ASSERT_LOCKED(); KASSERT(plen >= 0 && plen <= ar->ar_alen); - at = ar->ar_root; + at = srp_get_locked(&ar->ar_root); if (at == NULL) return (NULL); /* Default route */ if (plen == 0) { - dflt = at->at_default; - at->at_default = NULL; + node = srp_get_locked(&at->at_default); + srp_swap_locked(&at->at_default, NULL); art_table_free(ar, at); - return (dflt); + return (node); } /* @@ -474,12 +504,13 @@ art_delete(struct art_root *ar, struct a while (plen > (at->at_offset + at->at_bits)) { /* Do a single level route lookup. */ j = art_findex(at, addr); + node = srp_get_locked(&at->at_heap[j].node); /* If this is a leaf, there is no route to delete. */ - if (ISLEAF(at->at_heap[j])) + if (ISLEAF(node)) return (NULL); - at = SUBTABLE(at->at_heap[j]); + at = SUBTABLE(node); } i = art_bindex(at, addr, plen); @@ -494,24 +525,27 @@ art_delete(struct art_root *ar, struct a */ struct art_node * art_table_delete(struct art_root *ar, struct art_table *at, int i, - struct art_node *node) + struct art_node *an) { - struct art_node *next; + struct art_node *next, *node; #ifdef DIAGNOSTIC struct art_node *prev; +#endif - if (!ISLEAF(at->at_heap[i])) - prev = SUBTABLE(at->at_heap[i])->at_default; + node = srp_get_locked(&at->at_heap[i].node); +#ifdef DIAGNOSTIC + if (!ISLEAF(node)) + prev = srp_get_locked(&SUBTABLE(node)->at_default); else - prev = at->at_heap[i].node; + prev = node; - KASSERT(prev == node); + KASSERT(prev == an); #endif /* Get the next most specific route for the index `i'. */ if ((i >> 1) > 1) - next = at->at_heap[i >> 1].node; + next = srp_get_locked(&at->at_heap[i >> 1].node); else next = NULL; @@ -521,16 +555,16 @@ art_table_delete(struct art_root *ar, st * route pointer to all the corresponding fringe indices. */ if (i < at->at_minfringe) - art_allot(at, i, node, next); - else if (!ISLEAF(at->at_heap[i])) - SUBTABLE(at->at_heap[i])->at_default = next; + art_allot(at, i, an, next); + else if (!ISLEAF(node)) + srp_swap_locked(&SUBTABLE(node)->at_default, next); else - at->at_heap[i].node = next; + srp_swap_locked(&at->at_heap[i].node, next); /* We have removed an entry from this table. */ art_table_free(ar, at); - return (node); + return (an); } void @@ -539,17 +573,26 @@ art_table_ref(struct art_root *ar, struc at->at_refcnt++; } +static inline int +art_table_rele(struct art_table *at) +{ + if (at == NULL) + return (0); + + return (--at->at_refcnt == 0); +} + int art_table_free(struct art_root *ar, struct art_table *at) { - if (--at->at_refcnt == 0) { + if (art_table_rele(at)) { /* * Garbage collect this table and all its parents * that are empty. */ do { at = art_table_put(ar, at); - } while (at != NULL && --at->at_refcnt == 0); + } while (art_table_rele(at)); return (1); } @@ -564,9 +607,12 @@ int art_walk(struct art_root *ar, int (*f)(struct art_node *, void *), void *arg) { struct art_table *at; + struct art_node *node; int error; - at = ar->ar_root; + KERNEL_ASSERT_LOCKED(); + + at = srp_get_locked(&ar->ar_root); if (at == NULL) return (0); @@ -574,8 +620,9 @@ art_walk(struct art_root *ar, int (*f)(s * The default route should be processed here because the root * table does not have a parent. */ - if (at->at_default != NULL) { - error = (*f)(at->at_default, arg); + node = srp_get_locked(&at->at_default); + if (node != NULL) { + error = (*f)(node, arg); if (error) return (error); } @@ -588,6 +635,7 @@ art_table_walk(struct art_root *ar, stru int (*f)(struct art_node *, void *), void *arg) { struct art_node *next, *an = NULL; + struct art_node *node; int i, j, error = 0; uint32_t maxfringe = (at->at_minfringe << 1); @@ -604,8 +652,8 @@ art_table_walk(struct art_root *ar, stru * be processed more than once. */ for (i = max(j, 2); i < at->at_minfringe; i <<= 1) { - next = at->at_heap[i >> 1].node; - an = at->at_heap[i].node; + next = srp_get_locked(&at->at_heap[i >> 1].node); + an = srp_get_locked(&at->at_heap[i].node); if ((an != NULL) && (an != next)) { error = (*f)(an, arg); if (error) @@ -618,21 +666,23 @@ art_table_walk(struct art_root *ar, stru * Iterate fringe nodes. */ for (i = at->at_minfringe; i < maxfringe; i++) { - next = at->at_heap[i >> 1].node; - if (!ISLEAF(at->at_heap[i])) - an = SUBTABLE(at->at_heap[i])->at_default; + next = srp_get_locked(&at->at_heap[i >> 1].node); + node = srp_get_locked(&at->at_heap[i].node); + if (!ISLEAF(node)) + an = srp_get_locked(&SUBTABLE(node)->at_default); else - an = at->at_heap[i].node; + an = node; + if ((an != NULL) && (an != next)) { error = (*f)(an, arg); if (error) goto out; } - if (ISLEAF(at->at_heap[i])) + if (ISLEAF(node)) continue; - error = art_table_walk(ar, SUBTABLE(at->at_heap[i]), f, arg); + error = art_table_walk(ar, SUBTABLE(node), f, arg); if (error) break; } @@ -652,6 +702,7 @@ struct art_table * art_table_get(struct art_root *ar, struct art_table *parent, int j) { struct art_table *at; + struct art_node *node; void *at_heap; uint32_t lvl; @@ -694,7 +745,9 @@ art_table_get(struct art_root *ar, struc at->at_refcnt = 0; if (parent != NULL) { - at->at_default = parent->at_heap[j].node; + node = srp_get_locked(&parent->at_heap[j].node); + /* node isn't being deleted, no srp_finalize needed */ + srp_swap_locked(&at->at_default, node); at->at_offset = (parent->at_offset + parent->at_bits); } @@ -711,20 +764,22 @@ struct art_table * art_table_put(struct art_root *ar, struct art_table *at) { struct art_table *parent = at->at_parent; - uint32_t lvl = at->at_level; uint32_t j = at->at_index; + KASSERT(at->at_refcnt == 0); KASSERT(j != 0 && j != 1); - KASSERT(parent != NULL || j == -1); if (parent != NULL) { - KASSERT(lvl == parent->at_level + 1); + KASSERT(j != -1); + KASSERT(at->at_level == parent->at_level + 1); KASSERT(parent->at_refcnt >= 1); /* Give the route back to its parent. */ - parent->at_heap[j].node = at->at_default; + srp_swap_locked(&parent->at_heap[j].node, &at->at_default); } else { - ar->ar_root = NULL; + KASSERT(j == -1); + KASSERT(at->at_level == 0); + srp_swap_locked(&ar->ar_root, NULL); } mtx_enter(&art_table_gc_mtx); @@ -750,6 +805,11 @@ art_table_gc(void *null) while (at != NULL) { next = at->at_parent; + if (at->at_level == 0) + srp_finalize(at, "arttfini"); + else + srp_finalize(ASNODE(at), "arttfini"); + switch (AT_HEAPSIZE(at->at_bits)) { case AT_HEAPSIZE(4): pool_put(&at_heap_4_pool, at->at_heap); @@ -794,7 +854,8 @@ void art_allot(struct art_table *at, int i, struct art_node *old, struct art_node *new) { - int k = i; + struct art_node *node, *dflt; + int k = i; KASSERT(i < at->at_minfringe); @@ -805,12 +866,17 @@ again: /* Change fringe nodes. */ while (1) { - if (!ISLEAF(at->at_heap[k])) { - if (SUBTABLE(at->at_heap[k])->at_default == old) { - SUBTABLE(at->at_heap[k])->at_default = new; + node = srp_get_locked(&at->at_heap[k].node); + if (!ISLEAF(node)) { + dflt = srp_get_locked(&SUBTABLE(node)->at_default); + if (dflt == old) { + /* old node will be finalized later */ + srp_swap_locked(&SUBTABLE(node)->at_default, + new); } - } else if (at->at_heap[k].node == old) { - at->at_heap[k].node = new; + } else if (node == old) { + /* old node will be finalized later */ + srp_swap_locked(&at->at_heap[k].node, new); } if (k % 2) goto moveup; @@ -818,7 +884,8 @@ again: } nonfringe: - if (at->at_heap[k].node == old) + node = srp_get_locked(&at->at_heap[k].node); + if (node == old) goto again; moveon: if (k % 2) @@ -827,7 +894,11 @@ moveon: goto nonfringe; moveup: k >>= 1; - at->at_heap[k].node = new; + /* + * are we sure this is changing from old->new? + * old node is finalized by caller + */ + srp_swap_locked(&at->at_heap[k].node, new); /* Change non-fringe node. */ if (k != i) @@ -875,6 +946,8 @@ art_gc(void *null) while (an != NULL) { next = an->an_gc; + + srp_finalize(an, "artnfini"); pool_put(&an_pool, an); Index: art.h =================================================================== RCS file: /cvs/src/sys/net/art.h,v retrieving revision 1.13 diff -u -p -r1.13 art.h --- art.h 3 Jun 2016 03:59:43 -0000 1.13 +++ art.h 3 Jun 2016 10:36:34 -0000 @@ -19,13 +19,15 @@ #ifndef _NET_ART_H_ #define _NET_ART_H_ +#include + #define ART_MAXLVL 32 /* We currently use 32 levels for IPv6. */ /* * Root of the ART tables, equivalent to the radix head. */ struct art_root { - struct art_table *ar_root; /* First table */ + struct srp ar_root; /* First table */ uint8_t ar_bits[ART_MAXLVL]; /* Per level stride */ uint8_t ar_nlvl; /* Number of levels */ uint8_t ar_alen; /* Address length in bits */ @@ -59,8 +61,9 @@ struct art_node *art_insert(struct art_r int); struct art_node *art_delete(struct art_root *, struct art_node *, uint8_t *, int); -struct art_node *art_match(struct art_root *, uint8_t *); -struct art_node *art_lookup(struct art_root *, uint8_t *, int); +struct art_node *art_match(struct art_root *, uint8_t *, struct srp_ref *); +struct art_node *art_lookup(struct art_root *, uint8_t *, int, + struct srp_ref *); int art_walk(struct art_root *, int (*)(struct art_node *, void *), void *); Index: rtable.c =================================================================== RCS file: /cvs/src/sys/net/rtable.c,v retrieving revision 1.45 diff -u -p -r1.45 rtable.c --- rtable.c 1 Jun 2016 09:46:19 -0000 1.45 +++ rtable.c 3 Jun 2016 10:36:34 -0000 @@ -535,8 +535,8 @@ rtable_lookup(unsigned int rtableid, str { struct art_root *ar; struct art_node *an; - struct rtentry *rt; - struct srp_ref sr; + struct rtentry *rt = NULL; + struct srp_ref sr, nsr; uint8_t *addr; int plen; @@ -548,19 +548,22 @@ rtable_lookup(unsigned int rtableid, str /* No need for a perfect match. */ if (mask == NULL) { - an = art_match(ar, addr); + an = art_match(ar, addr, &nsr); if (an == NULL) - return (NULL); + goto out; } else { plen = rtable_satoplen(dst->sa_family, mask); if (plen == -1) return (NULL); - an = art_lookup(ar, addr, plen); + an = art_lookup(ar, addr, plen, &nsr); + if (an == NULL) + goto out; + /* Make sure we've got a perfect match. */ - if (an == NULL || an->an_plen != plen || - memcmp(an->an_dst, dst, dst->sa_len)) - return (NULL); + if (an->an_plen != plen || memcmp(an->an_dst, dst, + dst->sa_len)) + goto out; } #ifdef SMALL_KERNEL @@ -578,14 +581,13 @@ rtable_lookup(unsigned int rtableid, str memcmp(rt->rt_gateway, gateway, gateway->sa_len) == 0) break; } - if (rt == NULL) { - SRPL_LEAVE(&sr); - return (NULL); - } #endif /* SMALL_KERNEL */ + if (rt != NULL) + rtref(rt); - rtref(rt); SRPL_LEAVE(&sr); +out: + srp_leave(&nsr); return (rt); } @@ -596,7 +598,7 @@ rtable_match(unsigned int rtableid, stru struct art_root *ar; struct art_node *an; struct rtentry *rt = NULL; - struct srp_ref sr; + struct srp_ref sr, nsr; uint8_t *addr; #ifndef SMALL_KERNEL int hash; @@ -608,8 +610,7 @@ rtable_match(unsigned int rtableid, stru addr = satoaddr(ar, dst); - KERNEL_LOCK(); - an = art_match(ar, addr); + an = art_match(ar, addr, &nsr); if (an == NULL) goto out; @@ -634,6 +635,16 @@ rtable_match(unsigned int rtableid, stru threshold = (0xffff / npaths) + 1; + /* + * we have no protection against concurrent modification of the + * route list attached to the node, so we won't necessarily + * have the same number of routes. for most modifications, + * we'll pick a route that we wouldn't have if we only saw the + * list before or after the change. if we were going to use + * the last available route, but it got removed, we'll hit + * the end of the list and then pick the first route. + */ + mrt = SRPL_ENTER(&sr, &an->an_rtlist); while (hash > threshold && mrt != NULL) { if (mrt->rt_priority == rt->rt_priority) @@ -650,7 +661,7 @@ rtable_match(unsigned int rtableid, stru } #endif /* SMALL_KERNEL */ out: - KERNEL_UNLOCK(); + srp_leave(&nsr); return (rt); } @@ -661,12 +672,14 @@ rtable_insert(unsigned int rtableid, str { #ifndef SMALL_KERNEL struct rtentry *mrt; + struct srp_ref sr; #endif /* SMALL_KERNEL */ struct art_root *ar; struct art_node *an, *prev; uint8_t *addr; int plen; unsigned int rt_flags; + int error = 0; KERNEL_ASSERT_LOCKED(); @@ -679,33 +692,44 @@ rtable_insert(unsigned int rtableid, str if (plen == -1) return (EINVAL); + rtref(rt); /* guarantee rtfree wont do anything during insert */ + #ifndef SMALL_KERNEL /* Do not permit exactly the same dst/mask/gw pair. */ - an = art_lookup(ar, addr, plen); - if (an != NULL && an->an_plen == plen && - !memcmp(an->an_dst, dst, dst->sa_len)) { - struct rtentry *mrt; - int mpathok = ISSET(rt->rt_flags, RTF_MPATH); - - SRPL_FOREACH_LOCKED(mrt, &an->an_rtlist, rt_next) { - if (prio != RTP_ANY && - (mrt->rt_priority & RTP_MASK) != (prio & RTP_MASK)) - continue; - - if (!mpathok || - (mrt->rt_gateway->sa_len == gateway->sa_len && - !memcmp(mrt->rt_gateway, gateway, gateway->sa_len))){ - return (EEXIST); + an = art_lookup(ar, addr, plen, &sr); + srp_leave(&sr); /* an cannot go away while we have the lock */ + if (an != NULL) { + if (an->an_plen == plen && + !memcmp(an->an_dst, dst, dst->sa_len)) { + struct rtentry *mrt; + int mpathok = ISSET(rt->rt_flags, RTF_MPATH); + + SRPL_FOREACH_LOCKED(mrt, &an->an_rtlist, rt_next) { + if (prio != RTP_ANY && + (mrt->rt_priority & RTP_MASK) != + (prio & RTP_MASK)) + continue; + + if (!mpathok || + (mrt->rt_gateway->sa_len == + gateway->sa_len && + !memcmp(mrt->rt_gateway, gateway, + gateway->sa_len))) { + error = EEXIST; + goto leave; + } } } } #endif /* SMALL_KERNEL */ an = art_get(dst, plen); - if (an == NULL) - return (ENOBUFS); + if (an == NULL) { + error = ENOBUFS; + goto leave; + } - /* prepare for immediate operation if insert succeeds */ + /* prepare an for immediate operation if insert succeeds */ rt_flags = rt->rt_flags; rt->rt_flags &= ~RTF_MPATH; rt->rt_dest = dst; @@ -718,9 +742,11 @@ rtable_insert(unsigned int rtableid, str rt_next); rt->rt_flags = rt_flags; art_put(an); - - if (prev == NULL) - return ESRCH; + + if (prev == NULL) { + error = ESRCH; + goto leave; + } #ifndef SMALL_KERNEL an = prev; @@ -752,11 +778,12 @@ rtable_insert(unsigned int rtableid, str /* Put newly inserted entry at the right place. */ rtable_mpath_reprio(rtableid, dst, mask, rt->rt_priority, rt); #else - return (EEXIST); + error = EEXIST; #endif /* SMALL_KERNEL */ } - - return (0); +leave: + rtfree(rt); + return (error); } int @@ -765,6 +792,7 @@ rtable_delete(unsigned int rtableid, str { struct art_root *ar; struct art_node *an; + struct srp_ref sr; uint8_t *addr; int plen; #ifndef SMALL_KERNEL @@ -772,8 +800,6 @@ rtable_delete(unsigned int rtableid, str int npaths = 0; #endif /* SMALL_KERNEL */ - KERNEL_ASSERT_LOCKED(); - ar = rtable_get(rtableid, dst->sa_family); if (ar == NULL) return (EAFNOSUPPORT); @@ -781,10 +807,15 @@ rtable_delete(unsigned int rtableid, str addr = satoaddr(ar, dst); plen = rtable_satoplen(dst->sa_family, mask); - an = art_lookup(ar, addr, plen); + KERNEL_ASSERT_LOCKED(); + + an = art_lookup(ar, addr, plen, &sr); + srp_leave(&sr); /* an cant going away while we have the lock */ + if (an == NULL) + return (ESRCH); + /* Make sure we've got a perfect match. */ - if (an == NULL || an->an_plen != plen || - memcmp(an->an_dst, dst, dst->sa_len)) + if (an->an_plen != plen || memcmp(an->an_dst, dst, dst->sa_len)) return (ESRCH); #ifndef SMALL_KERNEL @@ -796,7 +827,7 @@ rtable_delete(unsigned int rtableid, str npaths++; if (npaths > 1) { - KASSERT(rt->rt_refcnt >= 2); + KASSERT(rt->rt_refcnt >= 1); SRPL_REMOVE_LOCKED(&rt_rc, &an->an_rtlist, rt, rtentry, rt_next); @@ -811,10 +842,10 @@ rtable_delete(unsigned int rtableid, str if (art_delete(ar, an, addr, plen) == NULL) return (ESRCH); - KASSERT(rt->rt_refcnt >= 2); + KASSERT(rt->rt_refcnt >= 1); SRPL_REMOVE_LOCKED(&rt_rc, &an->an_rtlist, rt, rtentry, rt_next); - art_put(an); + return (0); } @@ -879,6 +910,7 @@ rtable_mpath_reprio(unsigned int rtablei { struct art_root *ar; struct art_node *an; + struct srp_ref sr; uint8_t *addr; int plen; struct rtentry *mrt, *prt = NULL; @@ -890,13 +922,14 @@ rtable_mpath_reprio(unsigned int rtablei addr = satoaddr(ar, dst); plen = rtable_satoplen(dst->sa_family, mask); - an = art_lookup(ar, addr, plen); + KERNEL_ASSERT_LOCKED(); + + an = art_lookup(ar, addr, plen, &sr); + srp_leave(&sr); /* an cannot 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); - - KERNEL_ASSERT_LOCKED(); rtref(rt); /* keep rt alive in between remove and add */ SRPL_REMOVE_LOCKED(&rt_rc, &an->an_rtlist, rt, rtentry, rt_next);