Add ifa_try_ref() to simplify ifa handling inside epoch.

More and more code migrates from lock-based protection to the NET_EPOCH
 umbrella. It requires some logic changes, including, notably, refcount
 handling.

When we have an `ifa` pointer and we're running inside epoch we're
 guaranteed that this pointer will not be freed.
However, the following case can still happen:
 * in thread 1 we drop to 0 refcount for ifa and schedule its deletion.
 * in thread 2 we use this ifa and reference it
 * destroy callout kicks in
 * unhappy user reports bug

To address it, new `ifa_try_ref()` function is added, allowing to return
 failure when we try to reference `ifa` with 0 refcount.
Additionally, existing `ifa_ref()` is enforced with `KASSERT` to provide
 cleaner error in such scenarious.

Reviewed By: rstone, donner
Differential Revision: https://reviews.freebsd.org/D28639
MFC after:	1 week
This commit is contained in:
Alexander V. Chernikov 2021-02-16 20:12:58 +00:00
parent 9fdbf7eef5
commit 600eade2fb
2 changed files with 12 additions and 1 deletions

View File

@ -1857,8 +1857,18 @@ fail:
void
ifa_ref(struct ifaddr *ifa)
{
u_int old;
refcount_acquire(&ifa->ifa_refcnt);
old = refcount_acquire(&ifa->ifa_refcnt);
KASSERT(old > 0, ("%s: ifa %p has 0 refs", __func__, ifa));
}
int
ifa_try_ref(struct ifaddr *ifa)
{
NET_EPOCH_ASSERT();
return (refcount_acquire_if_not_zero(&ifa->ifa_refcnt));
}
static void

View File

@ -577,6 +577,7 @@ struct ifaddr {
struct ifaddr * ifa_alloc(size_t size, int flags);
void ifa_free(struct ifaddr *ifa);
void ifa_ref(struct ifaddr *ifa);
int ifa_try_ref(struct ifaddr *ifa);
/*
* Multicast address structure. This is analogous to the ifaddr