Clean up common ifaddr management:
- Unify reference count and lock initialization in a single function, ifa_init(). - Move tear-down from a macro (IFAFREE) to a function ifa_free(). - Move reference count bump from a macro (IFAREF) to a function ifa_ref(). - Instead of using a u_int protected by a mutex to refcount(9) for reference count management. The ifa_mtx is now used for exactly one ioctl, and possibly should be removed. MFC after: 3 weeks
This commit is contained in:
parent
2fc79768f3
commit
1f7e54e8c5
39
sys/net/if.c
39
sys/net/if.c
@ -758,7 +758,7 @@ if_attach_internal(struct ifnet *ifp, int vmove)
|
||||
socksize = roundup2(socksize, sizeof(long));
|
||||
ifasize = sizeof(*ifa) + 2 * socksize;
|
||||
ifa = malloc(ifasize, M_IFADDR, M_WAITOK | M_ZERO);
|
||||
IFA_LOCK_INIT(ifa);
|
||||
ifa_init(ifa);
|
||||
sdl = (struct sockaddr_dl *)(ifa + 1);
|
||||
sdl->sdl_len = socksize;
|
||||
sdl->sdl_family = AF_LINK;
|
||||
@ -775,7 +775,6 @@ if_attach_internal(struct ifnet *ifp, int vmove)
|
||||
sdl->sdl_len = masklen;
|
||||
while (namelen != 0)
|
||||
sdl->sdl_data[--namelen] = 0xff;
|
||||
ifa->ifa_refcnt = 1;
|
||||
TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link);
|
||||
/* Reliably crash if used uninitialized. */
|
||||
ifp->if_broadcastaddr = NULL;
|
||||
@ -896,7 +895,7 @@ if_purgeaddrs(struct ifnet *ifp)
|
||||
}
|
||||
#endif /* INET6 */
|
||||
TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
|
||||
IFAFREE(ifa);
|
||||
ifa_free(ifa);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1013,7 +1012,7 @@ if_detach_internal(struct ifnet *ifp, int vmove)
|
||||
if (!TAILQ_EMPTY(&ifp->if_addrhead)) {
|
||||
ifa = TAILQ_FIRST(&ifp->if_addrhead);
|
||||
TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
|
||||
IFAFREE(ifa);
|
||||
ifa_free(ifa);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1419,6 +1418,34 @@ if_rtdel(struct radix_node *rn, void *arg)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reference count functions for ifaddrs.
|
||||
*/
|
||||
void
|
||||
ifa_init(struct ifaddr *ifa)
|
||||
{
|
||||
|
||||
mtx_init(&ifa->ifa_mtx, "ifaddr", NULL, MTX_DEF);
|
||||
refcount_init(&ifa->ifa_refcnt, 1);
|
||||
}
|
||||
|
||||
void
|
||||
ifa_ref(struct ifaddr *ifa)
|
||||
{
|
||||
|
||||
refcount_acquire(&ifa->ifa_refcnt);
|
||||
}
|
||||
|
||||
void
|
||||
ifa_free(struct ifaddr *ifa)
|
||||
{
|
||||
|
||||
if (refcount_release(&ifa->ifa_refcnt)) {
|
||||
mtx_destroy(&ifa->ifa_mtx);
|
||||
free(ifa, M_IFADDR);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: Because sockaddr_dl has deeper structure than the sockaddr
|
||||
* structs used to represent other address families, it is necessary
|
||||
@ -1711,10 +1738,10 @@ link_rtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info)
|
||||
return;
|
||||
ifa = ifaof_ifpforaddr(dst, ifp);
|
||||
if (ifa) {
|
||||
IFAREF(ifa); /* XXX */
|
||||
ifa_ref(ifa); /* XXX */
|
||||
oifa = rt->rt_ifa;
|
||||
rt->rt_ifa = ifa;
|
||||
IFAFREE(oifa);
|
||||
ifa_free(oifa);
|
||||
if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
|
||||
ifa->ifa_rtrequest(cmd, rt, info);
|
||||
}
|
||||
|
@ -706,11 +706,14 @@ struct ifaddr {
|
||||
/* for compatibility with other BSDs */
|
||||
#define ifa_list ifa_link
|
||||
|
||||
#define IFA_LOCK_INIT(ifa) \
|
||||
mtx_init(&(ifa)->ifa_mtx, "ifaddr", NULL, MTX_DEF)
|
||||
#ifdef _KERNEL
|
||||
#define IFA_LOCK(ifa) mtx_lock(&(ifa)->ifa_mtx)
|
||||
#define IFA_UNLOCK(ifa) mtx_unlock(&(ifa)->ifa_mtx)
|
||||
#define IFA_DESTROY(ifa) mtx_destroy(&(ifa)->ifa_mtx)
|
||||
|
||||
void ifa_free(struct ifaddr *ifa);
|
||||
void ifa_init(struct ifaddr *ifa);
|
||||
void ifa_ref(struct ifaddr *ifa);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The prefix structure contains information about one prefix
|
||||
@ -741,24 +744,6 @@ struct ifmultiaddr {
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
#define IFAFREE(ifa) \
|
||||
do { \
|
||||
IFA_LOCK(ifa); \
|
||||
KASSERT((ifa)->ifa_refcnt > 0, \
|
||||
("ifa %p !(ifa_refcnt > 0)", ifa)); \
|
||||
if (--(ifa)->ifa_refcnt == 0) { \
|
||||
IFA_DESTROY(ifa); \
|
||||
free(ifa, M_IFADDR); \
|
||||
} else \
|
||||
IFA_UNLOCK(ifa); \
|
||||
} while (0)
|
||||
|
||||
#define IFAREF(ifa) \
|
||||
do { \
|
||||
IFA_LOCK(ifa); \
|
||||
++(ifa)->ifa_refcnt; \
|
||||
IFA_UNLOCK(ifa); \
|
||||
} while (0)
|
||||
|
||||
extern struct rwlock ifnet_lock;
|
||||
#define IFNET_LOCK_INIT() \
|
||||
|
@ -474,7 +474,7 @@ rtfree(struct rtentry *rt)
|
||||
* e.g other routes and ifaddrs.
|
||||
*/
|
||||
if (rt->rt_ifa)
|
||||
IFAFREE(rt->rt_ifa);
|
||||
ifa_free(rt->rt_ifa);
|
||||
/*
|
||||
* The key is separatly alloc'd so free it (see rt_setgate()).
|
||||
* This also frees the gateway, as they are always malloc'd
|
||||
@ -1126,7 +1126,7 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt,
|
||||
* This moved from below so that rnh->rnh_addaddr() can
|
||||
* examine the ifa and ifa->ifa_ifp if it so desires.
|
||||
*/
|
||||
IFAREF(ifa);
|
||||
ifa_ref(ifa);
|
||||
rt->rt_ifa = ifa;
|
||||
rt->rt_ifp = ifa->ifa_ifp;
|
||||
rt->rt_rmx.rmx_weight = 1;
|
||||
@ -1136,7 +1136,7 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt,
|
||||
if (rn_mpath_capable(rnh) &&
|
||||
rt_mpath_conflict(rnh, rt, netmask)) {
|
||||
if (rt->rt_ifa) {
|
||||
IFAFREE(rt->rt_ifa);
|
||||
ifa_free(rt->rt_ifa);
|
||||
}
|
||||
Free(rt_key(rt));
|
||||
RT_LOCK_DESTROY(rt);
|
||||
@ -1153,7 +1153,7 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt,
|
||||
*/
|
||||
if (rn == NULL) {
|
||||
if (rt->rt_ifa)
|
||||
IFAFREE(rt->rt_ifa);
|
||||
ifa_free(rt->rt_ifa);
|
||||
Free(rt_key(rt));
|
||||
RT_LOCK_DESTROY(rt);
|
||||
uma_zfree(V_rtzone, rt);
|
||||
@ -1409,8 +1409,8 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum)
|
||||
*/
|
||||
if (memcmp(rt->rt_ifa->ifa_addr,
|
||||
ifa->ifa_addr, ifa->ifa_addr->sa_len)) {
|
||||
IFAFREE(rt->rt_ifa);
|
||||
IFAREF(ifa);
|
||||
ifa_free(rt->rt_ifa);
|
||||
ifa_ref(ifa);
|
||||
rt->rt_ifp = ifa->ifa_ifp;
|
||||
rt->rt_ifa = ifa;
|
||||
}
|
||||
|
@ -694,7 +694,7 @@ route_output(struct mbuf *m, struct socket *so)
|
||||
rt->rt_ifa->ifa_rtrequest != NULL) {
|
||||
rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt,
|
||||
&info);
|
||||
IFAFREE(rt->rt_ifa);
|
||||
ifa_free(rt->rt_ifa);
|
||||
}
|
||||
if (info.rti_info[RTAX_GATEWAY] != NULL) {
|
||||
RT_UNLOCK(rt);
|
||||
@ -712,7 +712,7 @@ route_output(struct mbuf *m, struct socket *so)
|
||||
}
|
||||
if (info.rti_ifa != NULL &&
|
||||
info.rti_ifa != rt->rt_ifa) {
|
||||
IFAREF(info.rti_ifa);
|
||||
ifa_ref(info.rti_ifa);
|
||||
rt->rt_ifa = info.rti_ifa;
|
||||
rt->rt_ifp = info.rti_ifp;
|
||||
}
|
||||
|
@ -189,8 +189,7 @@ at_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
|
||||
* and link our new one on the end
|
||||
*/
|
||||
ifa = (struct ifaddr *)aa;
|
||||
IFA_LOCK_INIT(ifa);
|
||||
ifa->ifa_refcnt = 1;
|
||||
ifa_init(ifa);
|
||||
|
||||
/*
|
||||
* As the at_ifaddr contains the actual sockaddrs,
|
||||
@ -325,7 +324,7 @@ at_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
|
||||
/*
|
||||
* Now reclaim the reference.
|
||||
*/
|
||||
IFAFREE(ifa0);
|
||||
ifa_free(ifa0);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -377,11 +377,10 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
|
||||
}
|
||||
|
||||
ifa = &ia->ia_ifa;
|
||||
IFA_LOCK_INIT(ifa);
|
||||
ifa_init(ifa);
|
||||
ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr;
|
||||
ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
|
||||
ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask;
|
||||
ifa->ifa_refcnt = 1;
|
||||
|
||||
ia->ia_sockmask.sin_len = 8;
|
||||
ia->ia_sockmask.sin_family = AF_INET;
|
||||
@ -617,7 +616,7 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
|
||||
IN_MULTI_UNLOCK();
|
||||
}
|
||||
}
|
||||
IFAFREE(&ia->ia_ifa);
|
||||
ifa_free(&ia->ia_ifa);
|
||||
splx(s);
|
||||
|
||||
return (error);
|
||||
|
@ -784,9 +784,9 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
|
||||
if (ia == NULL)
|
||||
return (ENOBUFS);
|
||||
bzero((caddr_t)ia, sizeof(*ia));
|
||||
ifa_init(&ia->ia_ifa);
|
||||
LIST_INIT(&ia->ia6_memberships);
|
||||
/* Initialize the address and masks, and put time stamp */
|
||||
IFA_LOCK_INIT(&ia->ia_ifa);
|
||||
ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
|
||||
ia->ia_addr.sin6_family = AF_INET6;
|
||||
ia->ia_addr.sin6_len = sizeof(ia->ia_addr);
|
||||
@ -811,7 +811,6 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
|
||||
} else
|
||||
V_in6_ifaddr = ia;
|
||||
|
||||
ia->ia_ifa.ifa_refcnt = 1;
|
||||
IF_ADDR_LOCK(ifp);
|
||||
TAILQ_INSERT_TAIL(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
@ -1387,7 +1386,7 @@ in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
|
||||
* release another refcnt for the link from in6_ifaddr.
|
||||
* Note that we should decrement the refcnt at least once for all *BSD.
|
||||
*/
|
||||
IFAFREE(&oia->ia_ifa);
|
||||
ifa_free(&oia->ia_ifa);
|
||||
|
||||
splx(s);
|
||||
}
|
||||
|
@ -827,7 +827,7 @@ in6_ifdetach(struct ifnet *ifp)
|
||||
IF_ADDR_LOCK(ifp);
|
||||
TAILQ_REMOVE(&ifp->if_addrhead, (struct ifaddr *)ia, ifa_link);
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
IFAFREE(&ia->ia_ifa);
|
||||
ifa_free(&ia->ia_ifa);
|
||||
|
||||
/* also remove from the IPv6 address chain(itojun&jinmei) */
|
||||
oia = ia;
|
||||
@ -845,7 +845,7 @@ in6_ifdetach(struct ifnet *ifp)
|
||||
}
|
||||
}
|
||||
|
||||
IFAFREE(&oia->ia_ifa);
|
||||
ifa_free(&oia->ia_ifa);
|
||||
}
|
||||
|
||||
in6_pcbpurgeif0(&V_udbinfo, ifp);
|
||||
|
@ -1223,7 +1223,7 @@ nd6_dad_start(struct ifaddr *ifa, int delay)
|
||||
* (re)initialization.
|
||||
*/
|
||||
dp->dad_ifa = ifa;
|
||||
IFAREF(ifa); /* just for safety */
|
||||
ifa_ref(ifa); /* just for safety */
|
||||
dp->dad_count = V_ip6_dad_count;
|
||||
dp->dad_ns_icount = dp->dad_na_icount = 0;
|
||||
dp->dad_ns_ocount = dp->dad_ns_tcount = 0;
|
||||
@ -1258,7 +1258,7 @@ nd6_dad_stop(struct ifaddr *ifa)
|
||||
TAILQ_REMOVE(&V_dadq, (struct dadq *)dp, dad_list);
|
||||
free(dp, M_IP6NDP);
|
||||
dp = NULL;
|
||||
IFAFREE(ifa);
|
||||
ifa_free(ifa);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1301,7 +1301,7 @@ nd6_dad_timer(struct dadq *dp)
|
||||
TAILQ_REMOVE(&V_dadq, (struct dadq *)dp, dad_list);
|
||||
free(dp, M_IP6NDP);
|
||||
dp = NULL;
|
||||
IFAFREE(ifa);
|
||||
ifa_free(ifa);
|
||||
goto done;
|
||||
}
|
||||
|
||||
@ -1354,7 +1354,7 @@ nd6_dad_timer(struct dadq *dp)
|
||||
TAILQ_REMOVE(&V_dadq, (struct dadq *)dp, dad_list);
|
||||
free(dp, M_IP6NDP);
|
||||
dp = NULL;
|
||||
IFAFREE(ifa);
|
||||
ifa_free(ifa);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1432,7 +1432,7 @@ nd6_dad_duplicated(struct ifaddr *ifa)
|
||||
TAILQ_REMOVE(&V_dadq, (struct dadq *)dp, dad_list);
|
||||
free(dp, M_IP6NDP);
|
||||
dp = NULL;
|
||||
IFAFREE(ifa);
|
||||
ifa_free(ifa);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -170,8 +170,7 @@ ipx_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
|
||||
ipx_ifaddr = oia;
|
||||
ia = oia;
|
||||
ifa = (struct ifaddr *)ia;
|
||||
IFA_LOCK_INIT(ifa);
|
||||
ifa->ifa_refcnt = 1;
|
||||
ifa_init(ifa);
|
||||
TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
|
||||
ia->ia_ifp = ifp;
|
||||
ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr;
|
||||
@ -231,7 +230,7 @@ ipx_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
|
||||
else
|
||||
printf("Didn't unlink ipxifadr from list\n");
|
||||
}
|
||||
IFAFREE((&oia->ia_ifa));
|
||||
ifa_free(&oia->ia_ifa);
|
||||
return (0);
|
||||
|
||||
case SIOCAIFADDR:
|
||||
|
Loading…
Reference in New Issue
Block a user