Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 4 Aug 2011 12:50:43 +0300
From:      Kostik Belousov <kostikbel@gmail.com>
To:        Kohji Okuno <okuno.kohji@jp.panasonic.com>
Cc:        freebsd-current@freebsd.org
Subject:   Re: Bug: devfs is sure to have the bug.
Message-ID:  <20110804095043.GA17489@deviant.kiev.zoral.com.ua>
In-Reply-To: <20110804.114139.1356575228565324749.okuno.kohji@jp.panasonic.com>
References:  <20110803.141636.145758949453810779.okuno.kohji@jp.panasonic.com> <20110803.144423.2018247186416313018.okuno.kohji@jp.panasonic.com> <20110803135044.GM17489@deviant.kiev.zoral.com.ua> <20110804.114139.1356575228565324749.okuno.kohji@jp.panasonic.com>

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

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

On Thu, Aug 04, 2011 at 11:41:39AM +0900, Kohji Okuno wrote:
> Hello Kostik,
>=20
> From: Kostik Belousov <kostikbel@gmail.com>
> Subject: Re: Bug: devfs is sure to have the bug.
> Date: Wed, 3 Aug 2011 16:50:44 +0300
> > I think the problem you described is real, and suggested change is righ=
t.
> > Initially, I thought that we should work with devfs_generation as with
> > the atomic type due to unlocked access in the devfs_populate(), but then
> > convinced myself that this is not needed.
> >=20
> > But also, I think there is another half of the problem. Namely,
> > devfs_lookup() calls devfs_populate_vp(), and then does lookup with the
> > help of devfs_lookupx(). We will miss the generation update
> > happen after the drop of the dm_lock in devfs_populate_vp() to reacquire
> > the directory vnode lock.
> >=20
> > I propose the change below, consisting of your fix and also retry of
> > population and lookup in case generations do not match for ENOENT
> >case.
> >=20
> > diff --git a/sys/fs/devfs/devfs_devs.c b/sys/fs/devfs/devfs_devs.c
> > index d72ada0..8ff9bc2 100644
> > --- a/sys/fs/devfs/devfs_devs.c
> > +++ b/sys/fs/devfs/devfs_devs.c
> > @@ -63,7 +63,7 @@ static MALLOC_DEFINE(M_CDEVP, "DEVFS1", "DEVFS cdev_p=
riv storage");
> > =20
> >  static SYSCTL_NODE(_vfs, OID_AUTO, devfs, CTLFLAG_RW, 0, "DEVFS filesy=
stem");
> > =20
> > -static unsigned devfs_generation;
> > +unsigned devfs_generation;
> >  SYSCTL_UINT(_vfs_devfs, OID_AUTO, generation, CTLFLAG_RD,
> >  	&devfs_generation, 0, "DEVFS generation number");
> > =20
> > @@ -630,13 +630,15 @@ devfs_populate_loop(struct devfs_mount *dm, int c=
leanup)
> >  void
> >  devfs_populate(struct devfs_mount *dm)
> >  {
> > +	unsigned gen;
> > =20
> >  	sx_assert(&dm->dm_lock, SX_XLOCKED);
> > -	if (dm->dm_generation =3D=3D devfs_generation)
> > +	gen =3D devfs_generation;
> > +	if (dm->dm_generation =3D=3D gen)
> >  		return;
> >  	while (devfs_populate_loop(dm, 0))
> >  		continue;
> > -	dm->dm_generation =3D devfs_generation;
> > +	dm->dm_generation =3D gen;
> >  }
> > =20
> >  /*
> > diff --git a/sys/fs/devfs/devfs_int.h b/sys/fs/devfs/devfs_int.h
> > index cdc6aba..cb01ad1 100644
> > --- a/sys/fs/devfs/devfs_int.h
> > +++ b/sys/fs/devfs/devfs_int.h
> > @@ -71,6 +71,8 @@ struct cdev_priv {
> > =20
> >  #define	cdev2priv(c)	member2struct(cdev_priv, cdp_c, c)
> > =20
> > +extern unsigned devfs_generation;
> > +
> >  struct cdev	*devfs_alloc(int);
> >  int	devfs_dev_exists(const char *);
> >  void	devfs_free(struct cdev *);
> > diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c
> > index 955bd8b..2603caa 100644
> > --- a/sys/fs/devfs/devfs_vnops.c
> > +++ b/sys/fs/devfs/devfs_vnops.c
> > @@ -188,7 +188,7 @@ devfs_clear_cdevpriv(void)
> >   * On success devfs_populate_vp() returns with dmp->dm_lock held.
> >   */
> >  static int
> > -devfs_populate_vp(struct vnode *vp)
> > +devfs_populate_vp(struct vnode *vp, int dm_locked)
> >  {
> >  	struct devfs_dirent *de;
> >  	struct devfs_mount *dmp;
> > @@ -199,7 +199,8 @@ devfs_populate_vp(struct vnode *vp)
> >  	dmp =3D VFSTODEVFS(vp->v_mount);
> >  	locked =3D VOP_ISLOCKED(vp);
> > =20
> > -	sx_xlock(&dmp->dm_lock);
> > +	if (!dm_locked)
> > +		sx_xlock(&dmp->dm_lock);
> >  	DEVFS_DMP_HOLD(dmp);
> > =20
> >  	/* Can't call devfs_populate() with the vnode lock held. */
> > @@ -242,7 +243,7 @@ devfs_vptocnp(struct vop_vptocnp_args *ap)
> > =20
> >  	dmp =3D VFSTODEVFS(vp->v_mount);
> > =20
> > -	error =3D devfs_populate_vp(vp);
> > +	error =3D devfs_populate_vp(vp, 0);
> >  	if (error !=3D 0)
> >  		return (error);
> > =20
> > @@ -643,7 +644,7 @@ devfs_getattr(struct vop_getattr_args *ap)
> >  	struct devfs_mount *dmp;
> >  	struct cdev *dev;
> > =20
> > -	error =3D devfs_populate_vp(vp);
> > +	error =3D devfs_populate_vp(vp, 0);
> >  	if (error !=3D 0)
> >  		return (error);
> > =20
> > @@ -903,7 +904,7 @@ devfs_lookupx(struct vop_lookup_args *ap, int *dm_u=
nlock)
> > =20
> >  		if (cdev =3D=3D NULL)
> >  			sx_xlock(&dmp->dm_lock);
> > -		else if (devfs_populate_vp(dvp) !=3D 0) {
> > +		else if (devfs_populate_vp(dvp, 0) !=3D 0) {
> >  			*dm_unlock =3D 0;
> >  			sx_xlock(&dmp->dm_lock);
> >  			if (DEVFS_DMP_DROP(dmp)) {
> > @@ -966,19 +967,30 @@ devfs_lookupx(struct vop_lookup_args *ap, int *dm=
_unlock)
> >  static int
> >  devfs_lookup(struct vop_lookup_args *ap)
> >  {
> > -	int j;
> >  	struct devfs_mount *dmp;
> > -	int dm_unlock;
> > +	int error, dm_unlock;
> > =20
> > -	if (devfs_populate_vp(ap->a_dvp) !=3D 0)
> > +	dm_unlock =3D 0;
> > +retry:
> > +	if (devfs_populate_vp(ap->a_dvp, dm_unlock) !=3D 0)
> >  		return (ENOTDIR);
> > =20
> >  	dmp =3D VFSTODEVFS(ap->a_dvp->v_mount);
> >  	dm_unlock =3D 1;
> > -	j =3D devfs_lookupx(ap, &dm_unlock);
> > -	if (dm_unlock =3D=3D 1)
> > +	error =3D devfs_lookupx(ap, &dm_unlock);
> > +	if (error =3D=3D ENOENT) {
> > +		if (dm_unlock)
> > +			sx_assert(&dmp->dm_lock, SA_XLOCKED);
> > +		else {
> > +			sx_xlock(&dmp->dm_lock);
> > +			dm_unlock =3D 1;
> > +		}
> > +		if (devfs_generation !=3D dmp->dm_generation)
> > +			goto retry;
> > +	}
> > +	if (dm_unlock)
> >  		sx_xunlock(&dmp->dm_lock);
> > -	return (j);
> > +	return (error);
> >  }
> > =20
> >  static int
> > @@ -1202,7 +1214,7 @@ devfs_readdir(struct vop_readdir_args *ap)
> >  	}
> > =20
> >  	dmp =3D VFSTODEVFS(ap->a_vp->v_mount);
> > -	if (devfs_populate_vp(ap->a_vp) !=3D 0) {
> > +	if (devfs_populate_vp(ap->a_vp, 0) !=3D 0) {
> >  		if (tmp_ncookies !=3D NULL)
> >  			ap->a_ncookies =3D tmp_ncookies;
> >  		return (EIO);
> > @@ -1565,7 +1577,7 @@ devfs_symlink(struct vop_symlink_args *ap)
> >  	if (error)
> >  		return(error);
> >  	dmp =3D VFSTODEVFS(ap->a_dvp->v_mount);
> > -	if (devfs_populate_vp(ap->a_dvp) !=3D 0)
> > +	if (devfs_populate_vp(ap->a_dvp, 0) !=3D 0)
> >  		return (ENOENT);
> > =20
> >  	dd =3D ap->a_dvp->v_data;
>=20
> Thank you for your comment.
> But, now I'm using 8.1-RELEASE. May I have advice about 8.X ?
Do you mean a patch for the stable/8 ? I believe it is enough to
apply rev. 211628 to stable/8, then the patch I posted yesterday
should be compilable.

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

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (FreeBSD)

iEYEARECAAYFAk46a3MACgkQC3+MBN1Mb4hCDACg6RkKaszL0UO2d2dqfqZT/Ouq
I7sAoPBZ0w5jX7/wPR+H4qUXLTVfpK9z
=c1bA
-----END PGP SIGNATURE-----

--KQOSl2CQwBKYGM8f--



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