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)
 {

Reply via email to