I am writing a block device driver with a raw (character device)
interface just as described in any book on Unix device driver
programming. But unlike the examples in these books (and *like*
most real-life disk drivers), mine also has to do ioctls through
its raw device. A couple of months ago I posted a question how
to coordinate, in this context the execution of ioctl requests
and of block read/write requests.
Meanwhile, I hit upon the source of a "real" disk driver which
solved the problem as follows:
In the ioctl function, it just stores its arguments in static
variables. It then queues, through a call to the strategy routine,
a private static buf structure which exists for this sole purpose,
and finally does an iowait() on this buf. Of course it makes sure
that any further ioctl calls are put to sleep until this special
buf is free again.
The start routine checks, for each buf it dequeues, whether its
address is that of this special buf. If so, it executes the ioctl
function from the stored arguments and then calls iodone() on the
buf normally, waking up the process that called the ioctl function.
It seems to work, but I am not quite comfortable with it yet.
Is this how it is normally done? Do you see any flaws in this
scheme? Could iowait() and iodone() expect something in the buf
structure that the fake buf doesn't have, or do something to it
that will cause problems if the buf isn't a real one created by the
kernel or by physio()? Could it create a problem that b_bcount is
zero if the ioctl function hasn't any data to transfer? I once
noticed that iomap() panics if called for a buf with b_bcount==0,
which at the time seemed like an excessive reaction to me; but
iowait() and iodone() don't seem to mind.
Any comments welcome.
Tilman Schmidt Phone: +49 221 8299 275
Sema Group Deutschland GmbH Fax: +49 221 8299 266