Subject: Re: Understanding foo_open, foo_read, etc.
To: Peter Seebach <>
From: Quentin Garnier <>
List: tech-kern
Date: 08/29/2006 22:15:05
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

On Tue, Aug 29, 2006 at 02:42:23PM -0500, Peter Seebach wrote:
> I am looking at trying to update an import (zaptel-netbsd) from FreeBSD, =
> I am not understanding some of the code in it.  Looking around, I find th=
> I am completely stumped on a significant aspect of how drivers are suppos=
> to work.
> In general, looking through the system, I find a number of drivers with
> functions with names like foo_open, foo_read, and foo_close.  In some
> cases, foo_read takes a 'struct file *' as its first argument; in some,
> it takes the device's softc.  I don't know why!

It really depends on what the file descriptor points to.

> For instance, rnd.c's rndread is:
> int rndread(dev_t dev, struct uio *uio, int ioflag);
> The only example I see in /dev/*/*.c of the other form is dmover_io, which
> seems a bit odd.
> Looking at the code in an older port of zaptel-bsd to NetBSD, I see:
> 	dev_type_open(ztopen);
> 	const struct cdevsw zaptel_cdevsw =3D {
> 		ztopen, noclose, noread, nowrite, noioctl, nostop, notty,
> 		nopoll, nommap, nokqfilter, 0
> 	};
> Then, moments later:
> 	static struct fileops zt_fileops =3D {
> 		.fo_close =3D zt_close,
> 		.fo_ioctl =3D zt_ioctl,
> 	#ifdef __NetBSD__
> 		.fo_fcntl =3D zt_fcntl,
> 	#endif
> 		.fo_read =3D zt_read,
> 		.fo_write =3D zt_write,
> 		.fo_poll =3D  zt_poll,
> 		.fo_stat =3D zt_stat,
> 	#ifndef __NetBSD__
> 		.fo_kqfilter =3D zt_kqfilter
> 	#endif
> 	};
> I don't think I understand this.  What are the circumstances under which =
> would fill in 'file *' objects with fileops structures, instead of a cdev=

Look closely at the defined fields of that struct fileops.  There's one
missing:  open.  That's because the file descriptor is never opened
through the fileops, it is instead cloned when the device node is

> My vague theory is that, if functions matching the cdevsw prototypes were
> created and put into the cdevsw structure, it would not be necessary to
> allocate a file and fill it with file ops, because the device would someh=
> magically know to use its cdevsw operations.  But someone who has done th=

There's nothing magical here, look at miscfs/specfs/specfs_vnops.c.

> successfully (and therefore, who presumably understands it better than I =
> thought it was better to do it the other way...

It depends what you want to achieve.  From what you describe, I'd say
you're in confronted to a cloning device, i.e. a device driver that
exposes a single node that can be opened multiple times and result in
as many instances for the userland.

Other examples of this are bpf(4) and tap(4).  I advise reading the code
of the latter, I wrote it mainly as an example of those techniques,
although it's a bit complicated because both aspects of the device are
available:  you either use /dev/tap when you don't know which device you
intend to use, but you can also use /dev/tapN to directly access one
instance of the driver.  bpf(4) is different:  the cdevsw part only
implements the open() method, the rest appears in the fileops to be used
after the file descriptor was cloned.

Not sure if I'm very clear, but you should understand the code better

Quentin Garnier - -
"When I find the controls, I'll go where I like, I'll know where I want
to be, but maybe for now I'll stay right here on a silent sea."
KT Tunstall, Silent Sea, Eye to the Telescope, 2004.

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

Version: GnuPG v1.4.3 (NetBSD)