Module Name: src Committed By: ozaki-r Date: Fri Sep 22 05:05:32 UTC 2017
Modified Files: src/sys/net: route.c Log Message: Remove the global lock for rtcache Thanks to removal of LIST_ENTRY of struct route, rtcaches are accessed only by their users. And in existing usages a rtcache is guranteed to be not accessed simultaneously. So the rtcache framework doesn't need any exclusion controls in itself. To generate a diff of this commit: cvs rdiff -u -r1.199 -r1.200 src/sys/net/route.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/net/route.c diff -u src/sys/net/route.c:1.199 src/sys/net/route.c:1.200 --- src/sys/net/route.c:1.199 Thu Sep 21 07:15:34 2017 +++ src/sys/net/route.c Fri Sep 22 05:05:32 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: route.c,v 1.199 2017/09/21 07:15:34 ozaki-r Exp $ */ +/* $NetBSD: route.c,v 1.200 2017/09/22 05:05:32 ozaki-r Exp $ */ /*- * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc. @@ -97,7 +97,7 @@ #endif #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: route.c,v 1.199 2017/09/21 07:15:34 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: route.c,v 1.200 2017/09/22 05:05:32 ozaki-r Exp $"); #include <sys/param.h> #ifdef RTFLUSH_DEBUG @@ -169,8 +169,12 @@ static void rt_timer_timer(void *); * Locking notes: * - The routing table is protected by a global rwlock * - API: RT_RLOCK and friends - * - rtcaches are protected by a global rwlock - * - API: RTCACHE_RLOCK and friends + * - rtcaches are NOT protected by the framework + * - Callers must guarantee a rtcache isn't accessed simultaneously + * - How the constraint is guranteed in the wild + * - Protect a rtcache by a mutex (e.g., inp_route) + * - Make rtcache per-CPU and allow only accesses from softint + * (e.g., ipforward_rt_percpu) * - References to a rtentry is managed by reference counting and psref * - Reference couting is used for temporal reference when a rtentry * is fetched from the routing table @@ -213,8 +217,7 @@ static void rt_timer_timer(void *); */ /* - * Global locks for the routing table and rtcaches. - * Locking order: rtcache_lock => rt_lock + * Global lock for the routing table. */ static krwlock_t rt_lock __cacheline_aligned; #ifdef NET_MPSAFE @@ -231,21 +234,6 @@ static krwlock_t rt_lock __cacheline_al #define RT_ASSERT_WLOCK() do {} while (0) #endif -static krwlock_t rtcache_lock __cacheline_aligned; -#ifdef NET_MPSAFE -#define RTCACHE_RLOCK() rw_enter(&rtcache_lock, RW_READER) -#define RTCACHE_WLOCK() rw_enter(&rtcache_lock, RW_WRITER) -#define RTCACHE_UNLOCK() rw_exit(&rtcache_lock) -#define RTCACHE_ASSERT_WLOCK() KASSERT(rw_write_held(&rtcache_lock)) -#define RTCACHE_WLOCKED() rw_write_held(&rtcache_lock) -#else -#define RTCACHE_RLOCK() do {} while (0) -#define RTCACHE_WLOCK() do {} while (0) -#define RTCACHE_UNLOCK() do {} while (0) -#define RTCACHE_ASSERT_WLOCK() do {} while (0) -#define RTCACHE_WLOCKED() false -#endif - static uint64_t rtcache_generation; /* @@ -290,10 +278,6 @@ static void rt_ref(struct rtentry *); static struct rtentry * rtalloc1_locked(const struct sockaddr *, int, bool, bool); -static struct rtentry * - rtcache_validate_locked(struct route *); -static void rtcache_free_locked(struct route *); -static int rtcache_setdst_locked(struct route *, const struct sockaddr *); static void rtcache_ref(struct rtentry *, struct route *); @@ -503,9 +487,7 @@ rtcache_invalidate(void) if (rtcache_debug()) printf("%s: enter\n", __func__); - RTCACHE_WLOCK(); rtcache_generation++; - RTCACHE_UNLOCK(); } #ifdef RT_DEBUG @@ -569,23 +551,14 @@ retry: if (ISSET(rt->rt_flags, RTF_UPDATING) && /* XXX updater should be always able to acquire */ curlwp != rt_update_global.lwp) { - bool need_lock = false; if (!wait_ok || !rt_wait_ok()) goto miss; RT_UNLOCK(); splx(s); - /* XXX need more proper solution */ - if (RTCACHE_WLOCKED()) { - RTCACHE_UNLOCK(); - need_lock = true; - } - /* We can wait until the update is complete */ rt_update_wait(); - if (need_lock) - RTCACHE_WLOCK(); if (wlock) RT_WLOCK(); else @@ -775,17 +748,14 @@ rt_update_prepare(struct rtentry *rt) dlog(LOG_DEBUG, "%s: updating rt=%p lwp=%p\n", __func__, rt, curlwp); - RTCACHE_WLOCK(); RT_WLOCK(); /* If the entry is being destroyed, don't proceed the update. */ if (!ISSET(rt->rt_flags, RTF_UP)) { RT_UNLOCK(); - RTCACHE_UNLOCK(); return -1; } rt->rt_flags |= RTF_UPDATING; RT_UNLOCK(); - RTCACHE_UNLOCK(); mutex_enter(&rt_update_global.lock); while (rt_update_global.ongoing) { @@ -810,11 +780,9 @@ void rt_update_finish(struct rtentry *rt) { - RTCACHE_WLOCK(); RT_WLOCK(); rt->rt_flags &= ~RTF_UPDATING; RT_UNLOCK(); - RTCACHE_UNLOCK(); mutex_enter(&rt_update_global.lock); rt_update_global.ongoing = false; @@ -1679,7 +1647,6 @@ rt_timer_init(void) /* XXX should be in rt_init */ rw_init(&rt_lock); - rw_init(&rtcache_lock); LIST_INIT(&rttimer_queue_head); callout_init(&rt_timer_ch, CALLOUT_MPSAFE); @@ -1872,19 +1839,20 @@ _rtcache_init(struct route *ro, int flag rtcache_invariants(ro); KASSERT(ro->_ro_rt == NULL); - RTCACHE_ASSERT_WLOCK(); if (rtcache_getdst(ro) == NULL) return NULL; rt = rtalloc1(rtcache_getdst(ro), flag); - if (rt != NULL && ISSET(rt->rt_flags, RTF_UP)) { - ro->_ro_rt = rt; - ro->ro_rtcache_generation = rtcache_generation; - KASSERT(!ISSET(rt->rt_flags, RTF_UPDATING)); - rtcache_ref(rt, ro); - rt_unref(rt); - } else if (rt != NULL) + if (rt != NULL) { + RT_RLOCK(); + if (ISSET(rt->rt_flags, RTF_UP)) { + ro->_ro_rt = rt; + ro->ro_rtcache_generation = rtcache_generation; + rtcache_ref(rt, ro); + } + RT_UNLOCK(); rt_unref(rt); + } rtcache_invariants(ro); return ro->_ro_rt; @@ -1893,32 +1861,23 @@ _rtcache_init(struct route *ro, int flag struct rtentry * rtcache_init(struct route *ro) { - struct rtentry *rt; - RTCACHE_WLOCK(); - rt = _rtcache_init(ro, 1); - RTCACHE_UNLOCK(); - return rt; + + return _rtcache_init(ro, 1); } struct rtentry * rtcache_init_noclone(struct route *ro) { - struct rtentry *rt; - RTCACHE_WLOCK(); - rt = _rtcache_init(ro, 0); - RTCACHE_UNLOCK(); - return rt; + + return _rtcache_init(ro, 0); } struct rtentry * rtcache_update(struct route *ro, int clone) { - struct rtentry *rt; - RTCACHE_WLOCK(); + ro->_ro_rt = NULL; - rt = _rtcache_init(ro, clone); - RTCACHE_UNLOCK(); - return rt; + return _rtcache_init(ro, clone); } void @@ -1939,11 +1898,9 @@ rtcache_copy(struct route *new_ro, struc if (ret != 0) goto out; - RTCACHE_WLOCK(); new_ro->_ro_rt = rt; new_ro->ro_rtcache_generation = rtcache_generation; rtcache_invariants(new_ro); - RTCACHE_UNLOCK(); out: rtcache_unref(rt, old_ro); return; @@ -1991,55 +1948,45 @@ rtcache_unref(struct rtentry *rt, struct #endif } -static struct rtentry * -rtcache_validate_locked(struct route *ro) +struct rtentry * +rtcache_validate(struct route *ro) { struct rtentry *rt = NULL; #ifdef NET_MPSAFE retry: #endif - rt = ro->_ro_rt; rtcache_invariants(ro); - if (ro->ro_rtcache_generation != rtcache_generation) { /* The cache is invalidated */ - rt = NULL; - goto out; + return NULL; } + rt = ro->_ro_rt; + if (rt == NULL) + return NULL; + RT_RLOCK(); - if (rt != NULL && (rt->rt_flags & RTF_UP) != 0) { + if ((rt->rt_flags & RTF_UP) == 0) { + rt = NULL; + goto out; + } #ifdef NET_MPSAFE - if (ISSET(rt->rt_flags, RTF_UPDATING)) { - if (rt_wait_ok()) { - RT_UNLOCK(); - RTCACHE_UNLOCK(); - /* We can wait until the update is complete */ - rt_update_wait(); - RTCACHE_RLOCK(); - goto retry; - } else { - rt = NULL; - } - } else -#endif - rtcache_ref(rt, ro); + if (ISSET(rt->rt_flags, RTF_UPDATING)) { + if (rt_wait_ok()) { + RT_UNLOCK(); + + /* We can wait until the update is complete */ + rt_update_wait(); + goto retry; + } else { + rt = NULL; + } } else - rt = NULL; - RT_UNLOCK(); +#endif + rtcache_ref(rt, ro); out: - return rt; -} - -struct rtentry * -rtcache_validate(struct route *ro) -{ - struct rtentry *rt; - - RTCACHE_RLOCK(); - rt = rtcache_validate_locked(ro); - RTCACHE_UNLOCK(); + RT_UNLOCK(); return rt; } @@ -2050,53 +1997,41 @@ rtcache_lookup2(struct route *ro, const const struct sockaddr *odst; struct rtentry *rt = NULL; - RTCACHE_RLOCK(); odst = rtcache_getdst(ro); - if (odst == NULL) { - RTCACHE_UNLOCK(); - RTCACHE_WLOCK(); + if (odst == NULL) goto miss; - } if (sockaddr_cmp(odst, dst) != 0) { - RTCACHE_UNLOCK(); - RTCACHE_WLOCK(); - rtcache_free_locked(ro); + rtcache_free(ro); goto miss; } - rt = rtcache_validate_locked(ro); + rt = rtcache_validate(ro); if (rt == NULL) { - RTCACHE_UNLOCK(); - RTCACHE_WLOCK(); ro->_ro_rt = NULL; goto miss; } rtcache_invariants(ro); - RTCACHE_UNLOCK(); if (hitp != NULL) *hitp = 1; return rt; miss: if (hitp != NULL) *hitp = 0; - if (rtcache_setdst_locked(ro, dst) == 0) + if (rtcache_setdst(ro, dst) == 0) rt = _rtcache_init(ro, clone); rtcache_invariants(ro); - RTCACHE_UNLOCK(); return rt; } -static void -rtcache_free_locked(struct route *ro) +void +rtcache_free(struct route *ro) { - RTCACHE_ASSERT_WLOCK(); - ro->_ro_rt = NULL; if (ro->ro_sa != NULL) { sockaddr_free(ro->ro_sa); @@ -2105,22 +2040,11 @@ rtcache_free_locked(struct route *ro) rtcache_invariants(ro); } -void -rtcache_free(struct route *ro) -{ - - RTCACHE_WLOCK(); - rtcache_free_locked(ro); - RTCACHE_UNLOCK(); -} - -static int -rtcache_setdst_locked(struct route *ro, const struct sockaddr *sa) +int +rtcache_setdst(struct route *ro, const struct sockaddr *sa) { KASSERT(sa != NULL); - RTCACHE_ASSERT_WLOCK(); - rtcache_invariants(ro); if (ro->ro_sa != NULL) { if (ro->ro_sa->sa_family == sa->sa_family) { @@ -2130,7 +2054,7 @@ rtcache_setdst_locked(struct route *ro, return 0; } /* free ro_sa, wrong family */ - rtcache_free_locked(ro); + rtcache_free(ro); } KASSERT(ro->_ro_rt == NULL); @@ -2143,18 +2067,6 @@ rtcache_setdst_locked(struct route *ro, return 0; } -int -rtcache_setdst(struct route *ro, const struct sockaddr *sa) -{ - int error; - - RTCACHE_WLOCK(); - error = rtcache_setdst_locked(ro, sa); - RTCACHE_UNLOCK(); - - return error; -} - const struct sockaddr * rt_settag(struct rtentry *rt, const struct sockaddr *tag) {