PERFORCE change 126352 for review
Kip Macy
kmacy at FreeBSD.org
Wed Sep 12 18:38:07 PDT 2007
http://perforce.freebsd.org/chv.cgi?CH=126352
Change 126352 by kmacy at kmacy_home:ethng on 2007/09/13 01:37:50
add rtalloc2 which does the same work as rtalloc1 but:
- internally locks the route shared except when bumping the refcount
- returns the route unlocked
plug locking holes introduced in previous revision of rtalloc1
Affected files ...
.. //depot/projects/ethng/src/sys/net/route.c#5 edit
Differences ...
==== //depot/projects/ethng/src/sys/net/route.c#5 (text+ko) ====
@@ -114,9 +114,7 @@
RTFREE(rt);
ro->ro_rt = NULL;
}
- ro->ro_rt = rtalloc1(&ro->ro_dst, 1, ignore);
- if (ro->ro_rt)
- RT_UNLOCK(ro->ro_rt);
+ ro->ro_rt = rtalloc2(&ro->ro_dst, 1, ignore);
}
/*
@@ -153,8 +151,121 @@
*/
newrt = rt = RNTORT(rn);
nflags = rt->rt_flags & ~ignflags;
+ if (report && (nflags & RTF_CLONING)) {
+ RADIX_NODE_HEAD_UNLOCK_SHARED(rnh);
+ RADIX_NODE_HEAD_LOCK(rnh);
+ /*
+ * We are apparently adding (report = 0 in delete).
+ * If it requires that it be cloned, do so.
+ * (This implies it wasn't a HOST route.)
+ */
+ err = rtrequest(RTM_RESOLVE, dst, NULL,
+ NULL, 0, &newrt);
+ if (err) {
+ if (!((rn = rnh->rnh_matchaddr(dst, rnh)) &&
+ (rn->rn_flags & RNF_ROOT) == 0)) {
+ RADIX_NODE_HEAD_UNLOCK(rnh);
+ goto miss2;
+ }
+ /*
+ * If the cloning didn't succeed, maybe
+ * what we have will do. Return that.
+ */
+ newrt = rt; /* existing route */
+ RT_LOCK(newrt);
+ RADIX_NODE_HEAD_UNLOCK(rnh);
+ RT_ADDREF(newrt);
+ goto miss2;
+ }
+ KASSERT(newrt, ("no route and no error"));
+ RT_LOCK(newrt);
+ RADIX_NODE_HEAD_UNLOCK(rnh);
+ if (newrt->rt_flags & RTF_XRESOLVE) {
+ /*
+ * If the new route specifies it be
+ * externally resolved, then go do that.
+ */
+ msgtype = RTM_RESOLVE;
+ goto miss2;
+ }
+ /* Inform listeners of the new route. */
+ bzero(&info, sizeof(info));
+ info.rti_info[RTAX_DST] = rt_key(newrt);
+ info.rti_info[RTAX_NETMASK] = rt_mask(newrt);
+ info.rti_info[RTAX_GATEWAY] = newrt->rt_gateway;
+ if (newrt->rt_ifp != NULL) {
+ info.rti_info[RTAX_IFP] =
+ newrt->rt_ifp->if_addr->ifa_addr;
+ info.rti_info[RTAX_IFA] = newrt->rt_ifa->ifa_addr;
+ }
+ rt_missmsg(RTM_ADD, &info, newrt->rt_flags, 0);
+ } else {
+ KASSERT(rt == newrt, ("locking wrong route"));
+ RT_LOCK(newrt);
+ RADIX_NODE_HEAD_UNLOCK_SHARED(rnh);
+ RT_ADDREF(newrt);
+ }
+ } else {
+ /*
+ * Either we hit the root or couldn't find any match,
+ * Which basically means
+ * "caint get there frm here"
+ */
+ rtstat.rts_unreach++;
RADIX_NODE_HEAD_UNLOCK_SHARED(rnh);
+ miss2: if (report) {
+ /*
+ * If required, report the failure to the supervising
+ * Authorities.
+ * For a delete, this is not an error. (report == 0)
+ */
+ bzero(&info, sizeof(info));
+ info.rti_info[RTAX_DST] = dst;
+ rt_missmsg(msgtype, &info, 0, err);
+ }
+ }
+ if (newrt)
+ RT_LOCK_ASSERT(newrt);
+ return (newrt);
+}
+
+/*
+ * Look up the route that matches the address given
+ * Or, at least try.. Create a cloned route if needed.
+ *
+ * The returned route, if any, is locked.
+ */
+struct rtentry *
+rtalloc2(struct sockaddr *dst, int report, u_long ignflags)
+{
+ struct radix_node_head *rnh = rt_tables[dst->sa_family];
+ struct rtentry *rt;
+ struct radix_node *rn;
+ struct rtentry *newrt;
+ struct rt_addrinfo info;
+ u_long nflags;
+ int err = 0, msgtype = RTM_MISS;
+
+ newrt = NULL;
+ /*
+ * Look up the address in the table for that Address Family
+ */
+ if (rnh == NULL) {
+ rtstat.rts_unreach++;
+ goto miss2;
+ }
+ RADIX_NODE_HEAD_LOCK_SHARED(rnh);
+ if ((rn = rnh->rnh_matchaddr(dst, rnh)) &&
+ (rn->rn_flags & RNF_ROOT) == 0) {
+ /*
+ * If we find it and it's not the root node, then
+ * get a reference on the rtentry associated.
+ */
+ newrt = rt = RNTORT(rn);
+ nflags = rt->rt_flags & ~ignflags;
if (report && (nflags & RTF_CLONING)) {
+ RADIX_NODE_HEAD_UNLOCK_SHARED(rnh);
+ RADIX_NODE_HEAD_LOCK(rnh);
/*
* We are apparently adding (report = 0 in delete).
* If it requires that it be cloned, do so.
@@ -163,29 +274,32 @@
err = rtrequest(RTM_RESOLVE, dst, NULL,
NULL, 0, &newrt);
if (err) {
- RADIX_NODE_HEAD_LOCK_SHARED(rnh);
if (!((rn = rnh->rnh_matchaddr(dst, rnh)) &&
- (rn->rn_flags & RNF_ROOT) == 0))
- goto miss;
+ (rn->rn_flags & RNF_ROOT) == 0)) {
+ RADIX_NODE_HEAD_UNLOCK(rnh);
+ goto miss2;
+ }
/*
* If the cloning didn't succeed, maybe
* what we have will do. Return that.
*/
newrt = rt; /* existing route */
RT_LOCK(newrt);
- RADIX_NODE_HEAD_UNLOCK_SHARED(rnh);
+ RADIX_NODE_HEAD_UNLOCK(rnh);
RT_ADDREF(newrt);
- goto miss;
+ RT_LOCK_DOWNGRADE(newrt);
+ goto miss2;
}
+ RT_LOCK_SHARED(newrt);
+ RADIX_NODE_HEAD_UNLOCK(rnh);
KASSERT(newrt, ("no route and no error"));
- RT_LOCK(newrt);
if (newrt->rt_flags & RTF_XRESOLVE) {
/*
* If the new route specifies it be
* externally resolved, then go do that.
*/
msgtype = RTM_RESOLVE;
- goto miss;
+ goto miss2;
}
/* Inform listeners of the new route. */
bzero(&info, sizeof(info));
@@ -201,7 +315,9 @@
} else {
KASSERT(rt == newrt, ("locking wrong route"));
RT_LOCK(newrt);
+ RADIX_NODE_HEAD_UNLOCK_SHARED(rnh);
RT_ADDREF(newrt);
+ RT_LOCK_DOWNGRADE(newrt);
}
} else {
/*
@@ -210,7 +326,6 @@
* "caint get there frm here"
*/
rtstat.rts_unreach++;
- miss:
RADIX_NODE_HEAD_UNLOCK_SHARED(rnh);
miss2: if (report) {
/*
@@ -225,6 +340,9 @@
}
if (newrt)
RT_LOCK_ASSERT(newrt);
+
+ RT_UNLOCK_SHARED(newrt);
+
return (newrt);
}
More information about the p4-projects
mailing list