Now that we have a single refcounting mechanism for route entries, I'd
like to use atomic operations and grab the KERNEL_LOCK only if a CPU is
dropping the last reference on an entry.

Currently this only matters for MPLS.  I intentionally use atomic_* ops
because I'd like to see be able to see if a counter goes negative.

For symmetry reasons I'm also moving the KERNEL_LOCK() inside rtalloc().
These two functions are my current targets.

Comments, oks?

Index: sys/net/route.c
===================================================================
RCS file: /cvs/src/sys/net/route.c,v
retrieving revision 1.258
diff -u -p -r1.258 route.c
--- sys/net/route.c     22 Oct 2015 17:19:38 -0000      1.258
+++ sys/net/route.c     22 Oct 2015 17:21:52 -0000
@@ -215,6 +215,7 @@ rtalloc(struct sockaddr *dst, int flags,
        info.rti_info[RTAX_DST] = dst;
 
        s = splsoftnet();
+       KERNEL_LOCK();
        rt = rtable_match(tableid, dst);
        if (rt != NULL) {
                if ((rt->rt_flags & RTF_CLONING) && ISSET(flags, RT_RESOLVE)) {
@@ -236,6 +237,7 @@ miss:
                if (ISSET(flags, RT_REPORT))
                        rt_missmsg(RTM_MISS, &info, 0, NULL, error, tableid);
        }
+       KERNEL_UNLOCK();
        splx(s);
        return (rt);
 }
@@ -337,7 +339,7 @@ rtalloc_mpath(struct sockaddr *dst, uint
 void
 rtref(struct rtentry *rt)
 {
-       rt->rt_refcnt++;
+       atomic_inc_int(&rt->rt_refcnt);
 }
 
 void
@@ -348,14 +350,16 @@ rtfree(struct rtentry *rt)
        if (rt == NULL)
                return;
 
-       if (--rt->rt_refcnt <= 0) {
+       if (atomic_dec_int_nv(&rt->rt_refcnt) <= 0) {
                KASSERT(!ISSET(rt->rt_flags, RTF_UP));
                KASSERT(!RT_ROOT(rt));
-               rttrash--;
+               atomic_dec_int(&rttrash);
                if (rt->rt_refcnt < 0) {
                        printf("rtfree: %p not freed (neg refs)\n", rt);
                        return;
                }
+
+               KERNEL_LOCK();
                rt_timer_remove_all(rt);
                ifa = rt->rt_ifa;
                if (ifa)
@@ -368,6 +372,8 @@ rtfree(struct rtentry *rt)
                if (rt->rt_gateway)
                        free(rt->rt_gateway, M_RTABLE, 0);
                free(rt_key(rt), M_RTABLE, 0);
+               KERNEL_UNLOCK();
+
                pool_put(&rtentry_pool, rt);
        }
 }
@@ -773,7 +779,7 @@ rtrequest1(int req, struct rt_addrinfo *
                rt->rt_flags &= ~RTF_UP;
                if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)
                        ifa->ifa_rtrequest(RTM_DELETE, rt);
-               rttrash++;
+               atomic_inc_int(&rttrash);
 
                if (ret_nrt != NULL)
                        *ret_nrt = rt;
Index: sys/netmpls/mpls_input.c
===================================================================
RCS file: /cvs/src/sys/netmpls/mpls_input.c,v
retrieving revision 1.50
diff -u -p -r1.50 mpls_input.c
--- sys/netmpls/mpls_input.c    23 Sep 2015 08:49:46 -0000      1.50
+++ sys/netmpls/mpls_input.c    22 Oct 2015 17:21:52 -0000
@@ -170,9 +170,7 @@ do_v6:
                        }
                }
 
-               KERNEL_LOCK();
                rt = rtalloc(smplstosa(smpls), RT_REPORT|RT_RESOLVE, 0);
-               KERNEL_UNLOCK();
                if (rt == NULL) {
                        /* no entry for this label */
 #ifdef MPLS_DEBUG
@@ -290,9 +288,7 @@ do_v6:
                if (ifp != NULL && rt_mpls->mpls_operation != MPLS_OP_LOCAL)
                        break;
 
-               KERNEL_LOCK();
                rtfree(rt);
-               KERNEL_UNLOCK();
                rt = NULL;
        }
 
@@ -323,11 +319,7 @@ do_v6:
        (*ifp->if_ll_output)(ifp, m, smplstosa(smpls), rt);
        KERNEL_UNLOCK();
 done:
-       if (rt) {
-               KERNEL_LOCK();
-               rtfree(rt);
-               KERNEL_UNLOCK();
-       }
+       rtfree(rt);
 }
 
 int
@@ -394,7 +386,7 @@ mpls_do_error(struct mbuf *m, int type, 
        struct in_ifaddr *ia;
        struct icmp *icp;
        struct ip *ip;
-       int nstk;
+       int nstk, error;
 
        for (nstk = 0; nstk < MPLS_INKERNEL_LOOP_MAX; nstk++) {
                if (m->m_len < sizeof(*shim) &&
@@ -427,9 +419,7 @@ mpls_do_error(struct mbuf *m, int type, 
                smpls->smpls_len = sizeof(*smpls);
                smpls->smpls_label = shim->shim_label & MPLS_LABEL_MASK;
 
-               KERNEL_LOCK();
                rt = rtalloc(smplstosa(smpls), RT_REPORT|RT_RESOLVE, 0);
-               KERNEL_UNLOCK();
                if (rt == NULL) {
                        /* no entry for this label */
                        m_freem(m);
@@ -442,19 +432,16 @@ mpls_do_error(struct mbuf *m, int type, 
                         * less interface we need to find some other IP to
                         * use as source.
                         */
-                       KERNEL_LOCK();
                        rtfree(rt);
-                       KERNEL_UNLOCK();
                        m_freem(m);
                        return (NULL);
                }
-               KERNEL_LOCK();
                rtfree(rt);
-               if (icmp_reflect(m, NULL, ia)) {
-                       KERNEL_UNLOCK();
-                       return (NULL);
-               }
+               KERNEL_LOCK();
+               error = icmp_reflect(m, NULL, ia);
                KERNEL_UNLOCK();
+               if (error)
+                       return (NULL);
 
                ip = mtod(m, struct ip *);
                /* stuff to fix up which is normaly done in ip_output */

Reply via email to