LACP kernel panics: /* unlocking is safe here */

Andrew Boyer aboyer at averesystems.com
Mon Apr 9 17:06:35 UTC 2012


Makes sense to me.

-Andrew

On Apr 7, 2012, at 4:02 AM, Andrew Thompson wrote:

> On 3 April 2012 00:35, John Baldwin <jhb at freebsd.org> wrote:
>> On Friday, March 30, 2012 6:04:24 pm Andrew Boyer wrote:
>>> While investigating a LACP issue, I turned on LACP_DEBUG on a debug kernel.
>> In this configuration it's easy to panic the kernel - just run 'ifconfig lagg0
>> laggproto lacp' on a lagg that's already in LACP mode and receiving LACP
>> messages.
>>> 
>>> The problem is that lagg_lacp_detach() drops the lagg wlock (with the
>> comment in the title), which allows incoming LACP messages to get through
>> lagg_input() while the structure is being destroyed in lacp_detach().
>>> 
>>> There's a very simple fix, but I don't know if it's the best way to fix it.
>> Resetting the protocol before calling sc_detach causes any further incoming
>> packets to be dropped until the lagg gets reconfigured.  Thoughts?
>> 
>> This looks sensible.
> 
> Changing the order also needs an additional check as LAGG_PROTO_NONE
> no longer means the detach is finished. If one ioctl sleeps then we
> may nullify all the pointers upon wake that have already been set by
> the other ioctl.
> 
> Does this look ok?
> 
> Index: if_lagg.c
> ===================================================================
> --- if_lagg.c	(revision 233252)
> +++ if_lagg.c	(working copy)
> @@ -950,11 +950,11 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t
> 			error = EPROTONOSUPPORT;
> 			break;
> 		}
> +		LAGG_WLOCK(sc);
> 		if (sc->sc_proto != LAGG_PROTO_NONE) {
> -			LAGG_WLOCK(sc);
> +			/* Reset protocol first in case detach unlocks */
> +			sc->sc_proto = LAGG_PROTO_NONE;
> 			error = sc->sc_detach(sc);
> -			/* Reset protocol and pointers */
> -			sc->sc_proto = LAGG_PROTO_NONE;
> 			sc->sc_detach = NULL;
> 			sc->sc_start = NULL;
> 			sc->sc_input = NULL;
> @@ -966,8 +966,11 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t
> 			sc->sc_lladdr = NULL;
> 			sc->sc_req = NULL;
> 			sc->sc_portreq = NULL;
> -			LAGG_WUNLOCK(sc);
> +		} else if (sc->sc_input != NULL) {
> +			/* Still detaching */
> +			error = EBUSY;
> 		}
> +		LAGG_WUNLOCK(sc);
> 		if (error != 0)
> 			break;
> 		for (int i = 0; i < (sizeof(lagg_protos) /

--------------------------------------------------
Andrew Boyer	aboyer at averesystems.com






More information about the freebsd-net mailing list