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:
rwatson 2009-06-21 19:30:33 +00:00
parent 2fc79768f3
commit 1f7e54e8c5
10 changed files with 62 additions and 54 deletions

View File

@ -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);
}

View File

@ -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() \

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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:

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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: