Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 22 Aug 2007 08:35:52 +0200
From:      Pawel Jakub Dawidek <pjd@FreeBSD.org>
To:        John Baldwin <jhb@freebsd.org>
Cc:        Alfred Perlstein <alfred@freebsd.org>, freebsd-arch@freebsd.org
Subject:   Re: Lockless uidinfo.
Message-ID:  <20070822063552.GC4187@garage.freebsd.pl>
In-Reply-To: <200708211753.34697.jhb@freebsd.org>
References:  <20070818120056.GA6498@garage.freebsd.pl> <200708211403.29293.jhb@freebsd.org> <20070821191902.GA4187@garage.freebsd.pl> <200708211753.34697.jhb@freebsd.org>

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

--PuGuTyElPB9bOcsM
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

On Tue, Aug 21, 2007 at 05:53:34PM -0400, John Baldwin wrote:
> On Tuesday 21 August 2007 03:19:02 pm Pawel Jakub Dawidek wrote:
> > > Memory barriers on another CPU don't mean anything about the CPU thre=
ad 2=20
> is=20
> > > on.  Memory barriers do not flush caches on other CPUs, etc.  Normall=
y=20
> when=20
> > > objects are refcounted in a table, the table holds a reference on the=
=20
> object,=20
> > > but that doesn't seem to be the case here. [...]
> >=20
> > But the memory barrier from 'mtx_lock(&uihashtbl_mtx)' above
> > 'if (uip->ui_ref > 0)' would do the trick and I can safely avoid using
> > atomic read in this if statement, right?
>=20
> Yes, though that may be rather non-obvious to other people, or to yoursel=
f 6=20
> months down the road.  You should probably document it.

Agreed, I added a comment that should explain it.

> > > I wouldn't use a more complex algo in uifree() unless the simple one =
is=20
> shown=20
> > > to perform badly.  Needless complexity is a hindrance to future=20
> maintenance.
> >=20
> > Of coure we could do that, but I was trying really hard to remove
> > contention in the common case. Before we used UIDINFO_LOCK() in the
> > common case, now you suggesting using global lock here, and I'd really,
> > really prefer using one atomic only.
>=20
> *sigh*  You ignored my last sentence.  You need to think about other peop=
le=20
> who come and read this later or yourself 12 months from now when you've p=
aged=20
> out all the uidinfo stuff from your head.
>=20
> Hmm, what happens if you get this:
>=20
> thread A
> --------
>=20
>  refcount_release() - drops to 0
>=20
>   preempted
>=20
>                                  thread B
>                                  --------
>                                  uihold() - refcount goes to 1
>                                  ...
>                                  uifree() - refcount goes to 0
>                                  removes object from table and frees it
>=20
>   resumes
>=20
>   mtx_lock(&uihashtbl);
>=20
>   sees refcount of 0 so tries to destroy object again
>=20
>  *BOOM* (corruption, panic, etc.)

Grr, good catch.

> This is the race that the current code handles by taking a reference
> on the uid while it drops the uidinfo lock to acquire the table lock.
>=20
> Probably you need to not drop the last reference unless you hold the=20
> uihashtbl_mtx, which means not using refcount_release() and manually use =
an=20
> atomic_cmpset_int() if the refcount is > 1 to drop a ref to optimize the=
=20
> common case:
>=20
> 	old =3D uip->ui_refs;
> 	if (old > 1) {
> 		if (atomic_cmpset_int(&uip->ui_refs, old, old - 1))
> 			return;
> 	}
>=20
> 	mtx_lock(&uihashtbl_mtx);
> 	if (refcount_release(&uip->ui_refs)) {
> 		/* remove from table and free */
> 	}
> 	mtx_unlock(&uihashtbl_mtx);

How about we relookup it after acquiring the uihashtbl_mtx lock?
Something like this (comments removed):

	uid_t uid;

	uid =3D uip->ui_uid;
	if (!refcount_release(&uip->ui_ref))
		return;
	mtx_lock(&uihashtbl_mtx);
	uip =3D uilookup(uid);
	if (uip !=3D NULL && uip->ui_ref =3D=3D 0) {
		LIST_REMOVE(uip, ui_hash);
		mtx_unlock(&uihashtbl_mtx);
		FREE(uip, M_UIDINFO);
		return;
	}
	mtx_unlock(&uihashtbl_mtx);

I updated the patch at:

	http://people.freebsd.org/~pjd/patches/uidinfo_waitfree.patch

--=20
Pawel Jakub Dawidek                       http://www.wheel.pl
pjd@FreeBSD.org                           http://www.FreeBSD.org
FreeBSD committer                         Am I Evil? Yes, I Am!

--PuGuTyElPB9bOcsM
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.4 (FreeBSD)

iD8DBQFGy9lIForvXbEpPzQRAkyOAJoCwVBu1Fnr1tcYreempKrSrzJg+ACg2Vw9
T95TsOerhH6jnArM9tD3pno=
=kw9m
-----END PGP SIGNATURE-----

--PuGuTyElPB9bOcsM--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20070822063552.GC4187>