Page MenuHomeFreeBSD

iflib: drain the admin task before detaching the interface
ClosedPublic

Authored by nick_spun.io on Sat, Jul 25, 4:08 AM.
Tags
None
Referenced Files
F166852051: D58452.id182666.diff
Mon, Aug 17, 3:12 AM
Unknown Object (File)
Sun, Aug 16, 9:08 AM
Unknown Object (File)
Fri, Aug 14, 8:28 PM
Unknown Object (File)
Fri, Aug 14, 12:57 PM
Unknown Object (File)
Fri, Aug 14, 8:05 AM
Unknown Object (File)
Thu, Aug 13, 1:47 AM
Unknown Object (File)
Thu, Aug 13, 1:46 AM
Unknown Object (File)
Thu, Aug 13, 1:36 AM

Details

Summary

iflib_device_deregister() sets IFC_IN_DETACH and relies on
_task_fn_admin() observing it, but a task that has already passed that
check keeps running to completion. It can still call
iflib_link_state_change(), which re-arms if_linktask after
ether_ifdetach() has already drained it. The link state change is then
left pending across iflib_rx_structures_free().

When the pending state is LINK_STATE_UP and the kernel has DEBUGNET, the
resulting ifnet_link_event reaches iflib_debugnet_init(), which
dereferences ctx->ifc_rxqs[0].ifr_fl after it has been freed:

panic: page fault, virtual address 0x12
iflib_debugnet_init()
debugnet_any_ifnet_update()
do_link_state_change()

0x12 is offsetof(struct iflib_fl, ifl_size). Reproduced by unloading
if_aq while the interface was administratively down but the PHY still
had link, so the admin task kept re-announcing LINK_STATE_UP.

Drain the admin task before ether_ifdetach(), so the if_linktask drain
that it performs is the last one. IFC_IN_DETACH is already set at that
point, so a task enqueued afterwards returns without touching the
context.

The register failure path grew the same drain in 439132310ae1; this
applies it to the normal detach path, which that change had used as its
reference for correct teardown ordering.

Signed-off-by: Nick Price <nick@spun.io>

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

This comment was removed by nick_spun.io.

I spent a while looking at this, and I think maybe we should do a taskqueue_drain_all() here instead. Some drivers (bnxt) use their own tasks registered via iflib_config_task_init that deal with link events and might be subject to the same issue.

kbowling added a subscriber: kbowling.

I tested @gallatin suggestion of taskqueue_drain_all instead and it seems right, here is a harness https://reviews.freebsd.org/D58720

This revision is now accepted and ready to land.Sat, Aug 8, 6:23 AM

I'm confused.. patch looks like its still using taskqueue_drain rather than taskqueue_drain_all

@gallatin yes sorry if I was confusing, my approval is conditional on implementing your taskqueue_drain_all suggestion which I've tested.