Subject: Explanation of the EBUSY error on device opening, bugs to fix
To: None <tech-kern@netbsd.org>
From: Emmanuel Dreyfus <manu@netbsd.org>
List: tech-kern
Date: 10/28/2001 18:01:39
Quick summary: I'm working on a pseudodevice driver, and when I try to
open it for writting, I get a EBUSY error. The open() method of the
driver is not invoked. (end of quick summary)

I've bloated my kernel with printf() debug messages, and I now know that
my EBUSY problem is coming from sys/vfs_subr:vfs_mountedon(), which is
in turn called by sys/miscfs/specfs/spec_vnops.c:spec_open(), which is
the chararacter device open method.

My EBUSY error is fired by this test in spec_open():
        /*
         * When running in secure mode, do not allow opens
         * for writing of /dev/mem, /dev/kmem, or character
         * devices whose corresponding block devices are
         * currently mounted.
         */
        if (securelevel >=3D 1) {
                if ((bdev =3D chrtoblk(dev)) !=3D (dev_t)NODEV &&
                    vfinddev(bdev, VBLK, &bvp) &&
                    (error =3D vfs_mountedon(bvp)))=20
                        return (error);

chrtoblk() mainly lookup an entry in chrtoblktbl[], which=A0is a static
array. Both are defined in sys/arch/$arch/$arch/conf.c. It maps
character devices to block devices. This is used mainly for disk devices
(it keeps the relation between rsd0a and sd0a for instance), other
character devices have a NODEV corresponding block device.

The first bug here is that I did not add my character device to this
array, with a corresponding NODEV block device. I'm not the first one to
do this mistake since character device 60 on macppc (PCI bus access
device) is also missing in the table. Because you can see the problem
only with securelevel >=3D 1, this is an easy bug to do.

I used the documentation at
http://www.netbsd.org/Documentation/kernel/pseudo/ to make my
pseudodevice driver. The information about this array is missing from
this document. I think this is the second bug that has to be fixed.

Next bug: I was reading entry #61 of the table, whereas there are only
59 entries on macppc. chrtoblk() checks that the requested device has a
major number less than nchrdev, and nchrdev is build as the size of the
cdevsw switch. It is accurate, since the driver won't work if it's not
in the cdevsw switch.

What's wrong is that chrtoblktbl[] can be smaller than nchrdev entries,
if someone has forgotten to add its device there. We should catch this
in chrtoblk(), since it does happen, and working in kernel mode with
uninitialized data which is outside of an array sounds really bad.
(Maybe someone pervert enough will find a security hole here ;o) )

I think the best way of doing it would be to issue an error at compile
time when chrtoblktbl[]=A0and the cdevsw switch do not have the same
length. Opinions?=20

--=20
Emmanuel Dreyfus
manu@netbsd.org