Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 6 Jun 2009 23:22:30 +0200
From:      Pawel Jakub Dawidek <pjd@FreeBSD.org>
To:        Nick Barkas <snb@freebsd.org>
Cc:        svn-src-head@freebsd.org, dwmalone@maths.tcd.ie, svn-src-all@freebsd.org, src-committers@freebsd.org
Subject:   Re: svn commit: r193375 - head/sys/ufs/ufs
Message-ID:  <20090606212229.GD2313@garage.freebsd.pl>
In-Reply-To: <20090606181405.GA2928@ebi.local>
References:  <200906030944.n539iM2K045164@svn.freebsd.org> <20090603210652.GD3821@garage.freebsd.pl> <20090606181405.GA2928@ebi.local>

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

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

On Sat, Jun 06, 2009 at 08:14:07PM +0200, Nick Barkas wrote:
> On Wed, Jun 03, 2009 at 11:06:52PM +0200, Pawel Jakub Dawidek wrote:
> > On Wed, Jun 03, 2009 at 09:44:22AM +0000, Sean Nicholas Barkas wrote:
> > > Author: snb
> > > Date: Wed Jun  3 09:44:22 2009
> > > New Revision: 193375
> > > URL: http://svn.freebsd.org/changeset/base/193375
> > >=20
> > > Log:
> > >   Add vm_lowmem event handler for dirhash. This will cause dirhashes =
to be
> > >   deleted when the system is low on memory. This ought to allow an in=
crease to
> > >   vfs.ufs.dirhash_maxmem on machines that have lots of memory, without
> > >   degrading performance by having too much memory reserved for dirhas=
h when
> > >   other things need it. The default value for dirhash_maxmem is being=
 kept at
> > >   2MB for now, though.
> > >  =20
> > >   This work was mostly done during the 2008 Google Summer of Code.
> > >  =20
> > >   Approved by:	dwmalone (mentor), re
> > >   MFC after:	3 months
> > [...]
> > > +static int
> > > +ufsdirhash_destroy(struct dirhash *dh)
> > > +{
> > [...]
> > > +	/* Remove it from the list and detach its memory. */
> > > +	TAILQ_REMOVE(&ufsdirhash_list, dh, dh_list);
> > [...]
> > > +static void
> > > +ufsdirhash_lowmem()
> > > +{
> > [...]
> > > +	/*=20
> > > +	 * Delete dirhashes not used for more than ufs_dirhashreclaimage=20
> > > +	 * seconds. If we can't get a lock on the dirhash, it will be skipp=
ed.
> > > +	 */
> > > +	for (dh =3D TAILQ_FIRST(&ufsdirhash_list); dh !=3D NULL; dh =3D=20
> > > +	    TAILQ_NEXT(dh, dh_list)) {
> > > +		if (!sx_try_xlock(&dh->dh_lock))
> > > +			continue;
> > > +		if (time_second - dh->dh_lastused > ufs_dirhashreclaimage)
> > > +			memfreed +=3D ufsdirhash_destroy(dh);
> > > +		/* Unlock if we didn't delete the dirhash */
> > > +		else
> > > +			ufsdirhash_release(dh);
> > > +	}
> > > +
> > > +	/*=20
> > > +	 * If not enough memory was freed, keep deleting hashes from the he=
ad=20
> > > +	 * of the dirhash list. The ones closest to the head should be the=
=20
> > > +	 * oldest.=20
> > > +	 */
> > > +	for (dh =3D TAILQ_FIRST(&ufsdirhash_list); memfreed < memwanted &&
> > > +	    dh !=3DNULL; dh =3D TAILQ_NEXT(dh, dh_list)) {
> > > +		if (!sx_try_xlock(&dh->dh_lock))
> > > +			continue;
> > > +		memfreed +=3D ufsdirhash_destroy(dh);
> > > +	}
> > > +	DIRHASHLIST_UNLOCK();
> > > +}
> >=20
> > I don't see how that works. If you remove dh from the tailq in
> > ufsdirhash_destroy(), you can't do 'dh =3D TAILQ_NEXT(dh, dh_list)' at =
the
> > end of the loop.
> >=20
> > You should use TAILQ_FOREACH_SAFE(3). In the second case you also need =
to
> > move this extra check into the loop, probably.
>=20
> Yes, I think you are right. Thanks for catching that. I think that, as
> written, both loops will only try to delete the first hash they can lock
> in ufsdirhash_list. I'll try to correct that.=20
>=20
> > In addition you drop DIRHASHLIST lock in ufsdirhash_destroy() during the
> > loop. Can't the tailq be modified from elsewhere? Or even from parallel
> > call to ufsdirhash_lowmem() (I don't think we serialize those)?
>=20
> The lock is held on the tailq while we are doing TAILQ_REMOVE(). It is
> only released for freeing data structures contained in dirhashes that
> have been removed from the tailq. I don't see how this would be a
> problem, but I certainly could be missing something. [...]

The ufsdirhash_destroy() function does this:

	TAILQ_REMOVE(&ufsdirhash_list, dh, dh_list);

Once you return from ufsdirhash_destroy(), dh is no longer on the queue,
so how this is suppose to work: dh =3D TAILQ_NEXT(dh, dh_list)?

TAILQ_NEXT() should panic on you when called for element which is not on
the queue, but we don't have such strict checks compiled-in by default.
Try to define QUEUE_MACRO_DEBUG somewhere in sys/queue.h to get the debug.

All in all, if you traverse the queue and want to remove current element
from inside the loop, TAILQ_FOREACH_SAFE() is for you.

> [...] But, I don't really
> understand why the lock is dropped within ufsdirhash_destroy(), anyway.
> Perhaps it is not necessary to do so.=20
>=20
> I mostly just copied the code needed out of ufsdirhash_recycle() to
> write ufsdirhash_destroy(). ufsdirhash_recycle() I think could be
> concurrently called (by ufsdirhash_build()) previously, with the lock on
> ufsdirhash_list lock dropped in the same place, and I don't think this
> caused any problems.

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

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

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

iD8DBQFKKt4VForvXbEpPzQRAjvPAJwIhUY1dVZSYbHPmadaG7JXtp5qdACePeeS
Zj1fgRN4QPs0K0jGmqbcMRQ=
=RG7Z
-----END PGP SIGNATURE-----

--d01dLTUuW90fS44H--



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