Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 9 Feb 2015 21:45:35 +0000
From:      "Bjoern A. Zeeb" <bz@FreeBSD.org>
To:        Randall Stewart <rrs@FreeBSD.org>
Cc:        svn-src-head@freebsd.org, svn-src-all@freebsd.org, src-committers@freebsd.org
Subject:   Re: svn commit: r278472 - in head/sys: netinet netinet6
Message-ID:  <38B8D2D0-862A-4DF5-9479-8EC234CF830B@FreeBSD.org>
In-Reply-To: <201502091928.t19JSC5P066293@svn.freebsd.org>
References:  <201502091928.t19JSC5P066293@svn.freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help

> On 09 Feb 2015, at 19:28 , Randall Stewart <rrs@FreeBSD.org> wrote:
>=20
> Author: rrs
> Date: Mon Feb  9 19:28:11 2015
> New Revision: 278472
> URL: https://svnweb.freebsd.org/changeset/base/278472
>=20
> Log:
>  This fixes a bug in the way that the LLE timers for nd6
>  and arp were being used. They basically would pass in the
>  mutex to the callout_init. Because they used this method
>  to the callout system, it was possible to "stop" the callout.
>  When flushing the table and you stopped the running callout, the
>  callout_stop code would return 1 indicating that it was going
>  to stop the callout (that was about to run on the callout_wheel =
blocked
>  by the function calling the stop). Now when 1 was returned, it would
>  lower the reference count one extra time for the stopped timer, then
>  a few lines later delete the memory. Of course the callout_wheel was
>  stuck in the lock code and would then crash since it was accessing
>  freed memory. By using callout_init(c, 1) we always get a 0 back
>  and the reference counting bug does not rear its head. We do have
>  to make a few adjustments to the callouts themselves though to make
>  sure it does the proper thing if rescheduled as well as gets the =
lock.
>=20
>  Commented upon by hiren and sbruno
>  See Phabricator D1777 for more details.
>=20
>  Commented upon by hiren and sbruno
>  Reviewed by:	adrian, jhb and bz

I have not reviewed this;  as a matter of fact you are aware that I =
still wanted to do that.


>  Sponsored by:	Netflix Inc.
>=20
> Modified:
>  head/sys/netinet/if_ether.c
>  head/sys/netinet/in.c
>  head/sys/netinet6/in6.c
>  head/sys/netinet6/nd6.c
>=20
> Modified: head/sys/netinet/if_ether.c
> =
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
> --- head/sys/netinet/if_ether.c	Mon Feb  9 19:21:54 2015	=
(r278471)
> +++ head/sys/netinet/if_ether.c	Mon Feb  9 19:28:11 2015	=
(r278472)
> @@ -166,10 +166,28 @@ arptimer(void *arg)
> 	struct ifnet *ifp;
>=20
> 	if (lle->la_flags & LLE_STATIC) {
> -		LLE_WUNLOCK(lle);
> 		return;
> 	}
> -
> +	LLE_WLOCK(lle);
> +	if (callout_pending(&lle->la_timer)) {
> +		/*
> +		 * Here we are a bit odd here in the treatment of=20
> +		 * active/pending. If the pending bit is set, it got
> +		 * rescheduled before I ran. The active
> +		 * bit we ignore, since if it was stopped
> +		 * in ll_tablefree() and was currently running
> +		 * it would have return 0 so the code would
> +		 * not have deleted it since the callout could
> +		 * not be stopped so we want to go through
> +		 * with the delete here now. If the callout
> +		 * was restarted, the pending bit will be back on and
> +		 * we just want to bail since the callout_reset would
> +		 * return 1 and our reference would have been removed
> +		 * by arpresolve() below.
> +		 */
> +		LLE_WUNLOCK(lle);
> + 		return;
> + 	}
> 	ifp =3D lle->lle_tbl->llt_ifp;
> 	CURVNET_SET(ifp->if_vnet);
>=20
>=20
> Modified: head/sys/netinet/in.c
> =
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
> --- head/sys/netinet/in.c	Mon Feb  9 19:21:54 2015	=
(r278471)
> +++ head/sys/netinet/in.c	Mon Feb  9 19:28:11 2015	=
(r278472)
> @@ -962,8 +962,7 @@ in_lltable_new(const struct sockaddr *l3
> 	lle->base.lle_refcnt =3D 1;
> 	lle->base.lle_free =3D in_lltable_free;
> 	LLE_LOCK_INIT(&lle->base);
> -	callout_init_rw(&lle->base.la_timer, &lle->base.lle_lock,
> -	    CALLOUT_RETURNUNLOCKED);
> +	callout_init(&lle->base.la_timer, 1);
>=20
> 	return (&lle->base);
> }
>=20
> Modified: head/sys/netinet6/in6.c
> =
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
> --- head/sys/netinet6/in6.c	Mon Feb  9 19:21:54 2015	=
(r278471)
> +++ head/sys/netinet6/in6.c	Mon Feb  9 19:28:11 2015	=
(r278472)
> @@ -2047,8 +2047,7 @@ in6_lltable_new(const struct sockaddr *l
> 	lle->base.lle_refcnt =3D 1;
> 	lle->base.lle_free =3D in6_lltable_free;
> 	LLE_LOCK_INIT(&lle->base);
> -	callout_init_rw(&lle->base.ln_timer_ch, &lle->base.lle_lock,
> -	    CALLOUT_RETURNUNLOCKED);
> +	callout_init(&lle->base.ln_timer_ch, 1);
>=20
> 	return (&lle->base);
> }
>=20
> Modified: head/sys/netinet6/nd6.c
> =
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
> --- head/sys/netinet6/nd6.c	Mon Feb  9 19:21:54 2015	=
(r278471)
> +++ head/sys/netinet6/nd6.c	Mon Feb  9 19:28:11 2015	=
(r278472)
> @@ -473,9 +473,28 @@ nd6_llinfo_timer(void *arg)
>=20
> 	KASSERT(arg !=3D NULL, ("%s: arg NULL", __func__));
> 	ln =3D (struct llentry *)arg;
> -	LLE_WLOCK_ASSERT(ln);
> +	LLE_WLOCK(ln);
> +	if (callout_pending(&ln->la_timer)) {
> +		/*
> +		 * Here we are a bit odd here in the treatment of=20
> +		 * active/pending. If the pending bit is set, it got
> +		 * rescheduled before I ran. The active
> +		 * bit we ignore, since if it was stopped
> +		 * in ll_tablefree() and was currently running
> +		 * it would have return 0 so the code would
> +		 * not have deleted it since the callout could
> +		 * not be stopped so we want to go through
> +		 * with the delete here now. If the callout
> +		 * was restarted, the pending bit will be back on and
> +		 * we just want to bail since the callout_reset would
> +		 * return 1 and our reference would have been removed
> +		 * by nd6_llinfo_settimer_locked above since canceled
> +		 * would have been 1.
> +		 */
> +		LLE_WUNLOCK(ln);
> +		return;
> +	}
> 	ifp =3D ln->lle_tbl->llt_ifp;
> -
> 	CURVNET_SET(ifp->if_vnet);
>=20
> 	if (ln->ln_ntick > 0) {
>=20

=E2=80=94=20
Bjoern A. Zeeb                                  Charles Haddon Spurgeon:
"Friendship is one of the sweetest joys of life.  Many might have failed
 beneath the bitterness of their trial  had they not found a friend."




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?38B8D2D0-862A-4DF5-9479-8EC234CF830B>