Subject: Re: bread() returns EINVAL during vfs mount
To: Yevgeny Binder <yevbee@comcast.net>
From: Bill Studenmund <wrstuden@netbsd.org>
List: tech-kern
Date: 08/22/2005 14:49:19
--OROCMA9jn6tkzFBc
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

On Sat, Aug 20, 2005 at 09:47:18PM -0500, Yevgeny Binder wrote:
> I've tried to follow the ffs code closely while developing hfs+ =20
> support, so it stumped me when I found that bread() invariably =20
> returns EINVAL in my VFS mount routine. I have a valid pointer to the =20
> volume's device node, devvp, obtained using the same ffs code:
>=20
>     NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
>     if ((error =3D namei(ndp)) !=3D 0)
>         return error;
>     devvp =3D ndp->ni_vp;
>=20
> ndp comes from the mount arguments, and args.fspec is presently set =20
> to "/dev/cd0a". I open this node and flush it:
>=20
>     if ((error =3D VOP_OPEN(devvp, FREAD, FSCRED, p)) !=3D 0)
>         goto error;
>=20
>     vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
>     error =3D vinvalbuf(devvp, V_SAVE, cred, p, 0, 0);
>     VOP_UNLOCK(devvp, 0);
>     if (error !=3D 0)
>         goto error;
>=20
> p also comes from the mount arguments, and cred =3D p ? p->p_ucred : =20
> NOCRED. Finally,
>=20
>     struct buf *bp =3D NULL;
>     error =3D bread(devvp, 16, 1536, cred, &bp);
>     if (bp !=3D NULL) {
>         /* memcpy() would take the place of the printf() below in =20
> the real implementation */
>         printf("bp->b_un.b_addr =3D %#x\n", (unsigned)bp->b_un.b_addr);
>         brelse(bp);
>     }
>=20
> (The block number and length are temporarily hardcoded for testing.) =20
> This always produces an error 22, EINVAL. Interestingly, bp is not =20
> NULL, and bp->b_un.b_addr points to a seemingly valid location, =20
> albeit one with meaningless data (always 0xDEADBEEF, followed by two =20
> pointers, followed by a bunch of zeroes). I know that the device and =20
> its contents at the specified block range are good, because I have =20
> userland code which calls pread() on that range and returns perfectly =20
> correct data.

The problem is that pread() permits i/o access that is not permitted with=
=20
the buffer cache system. So it covers over issues that bread() won't.

The problem is that you have to read full blocks. On a CD, that means 2k.=
=20
1536 is not an integer number of blocks, thus an EINVAL error.

> After trying dozens of changes that all resulted in the same error, =20
> the only possibility I can imagine is that I've somehow missed a =20
> subtle VFS call or preprocessor macro somewhere. But I've pored over =20
> the ffs code and I don't think I've left anything out. Could someone =20
> please outline the essential steps needed to go from receiving a VFS =20
> mount call to being able to call bread() successfully, including any =20
> vital preprocessor commands? I thought the above code was it, but =20
> then what's causing bread() to fail?

I think the problem is that you have drawn inspiration from file systems=20
that never face this issue. If someone ever built an ffs file system on a=
=20
CD, it would use 2k blocks, so all i/o would be 2k by nature and this=20
issue would never come up. :-|

Take care,

Bill

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

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (NetBSD)

iD8DBQFDCkheWz+3JHUci9cRAuRuAJ0exnLAJaieVnWR612TpNyM8WwRRwCfWy8d
hnblI8rW4kiarBWjqntr+ME=
=mks5
-----END PGP SIGNATURE-----

--OROCMA9jn6tkzFBc--