Driver development question

John Baldwin jhb at freebsd.org
Wed Jul 29 17:56:59 UTC 2009


On Wednesday 29 July 2009 1:23:46 pm Chris Harrer wrote:
> Warning LONG message below, I figured I'd give as much information as
> possible to try and help me along.
> 
> 
> > On Tuesday 21 July 2009 8:07:13 pm Alfred Perlstein wrote:
> > > * John Baldwin <jhb at freebsd.org> [090721 14:44] wrote:
> > > > On Tuesday 21 July 2009 2:34:21 am Marc Loerner wrote:
> > > > > Am Dienstag 21 Juli 2009 00:38:56 schrieb Sam Leffler:
> > > > > > John Baldwin wrote:
> > > > > > > On Friday 17 July 2009 11:10:17 am Chris Harrer wrote:
> > > > > > >> Hi All,
> > > > > > >>
> > > > > > >> I'm hoping someone can point me in the right direction...  I'm
> > > > > > >> developing a FreeBSD driver for a PCIe card.  The driver
> controls a
> > > > > > >> hardware device that has DRAM and various state information on
> it.  
> > I'm
> > > > > > >> trying to mimic functionality I have for other OS support such
> that 
> > I
> > > > > > >> can dump memory and state information from the card to a file I
> 
> > create
> > > > > > >> from within my driver (kernel module).
> > > > > > >>
> > > > > > >> For example, in a Linux driver I use filp_open to create the
> dump 
> > file
> > > > > > >> (represented by fp), then use fp->f_op->write to put
> information 
> > into
> > > > > > >> the file.
> > > > > > >>
> > > > > > >> FreeBSD doesn't have filp_* API's.  I've tried searching for 
> > example
> > > > > > >> drivers and googling for file API's from kernel modules to no 
> > avail. 
> > > > > > >> Can someone please offer some guidance as to how I might
> proceed 
> > here?
> > > > > > >>
> > > > > > >> Thanks in advance and any insight would be most appreciated!
> > > > > > >
> > > > > > > You can look at sys/kern/kern_ktrace.c to see how the ktrace() 
> > system
> > > > > > > call creates a file.  I think in general you will wind up using
> > > > > > > NDINIT/namei() (to lookup the vnode for a pathname) and then 
> > vn_open() /
> > > > > > > vn_rdwr() / vn_close().
> > > > > >
> > > > > > man alq(9).
> > > > > >
> > > > > > 	
> > > > > 
> > > > > Why not use kern_open, kern_close, kern_preadv, kern_pwritev?
> > > > 
> > > > Those affect the state of the current process by opening a new file 
> > > > descriptor, etc.  That is generally bad practice for a device driver
> to be 
> > > > interfering with a process' state, and it will not work for kernel 
> > threads.  
> > > > You can rather easily have userland open a file and then pass the file
> 
> > > > descriptor to a driver which can then do operations on a file
> directly.
> > > 
> > > If the vnode operations are annoying to wrap ones head around, one
> > > could have the driver defer this this to a kernel resident process
> > > that the driver would create on attach.
> > 
> > Kernel processes don't have file descriptor tables.
> 
> Hi All,
> 
> I'm hoping you can provide a bit more guidance here as I'm still struggling
> with this and I'm running out of ideas.  Again, what I want to do is, some
> event (interrupt from an intelligent PCIe card indicating it's "dead") will
> cause me to:
> 
> 1) Open/create a file
> 2) write raw/random/non-patterned/variable sized data to the file
> 3) close/save the file
> 
> from within my device driver.  To this point, I've tried several things
> using vn_open, vn_open_cred, alq_open and cutting/massaging the code from
> alq_open with no success.  I've done this from within the context of my
> interrupt handler as well as a timer (callout_init, callout_reset) thread as
> well as from a thread I create with kproc_create.  In each and every
> instance, I get the following crash:

The problem is that kernel threads do not have a valid file descriptor table, 
hence fd_cdir is NULL.  You could work around this if you create a dedicated 
kproc and set fd_cdir to rootvnode (but vref() rootvnode when you do this).  
You should also set fd_rdir and fd_jdir to rootvnode as well (also doing 
appropriate vref() of rootvnode for each reference).  Something like this:

	struct filedesc *fdp;

	fdp = curthread->td_proc->p_fd;
	FILEDESC_XLOCK(fdp);
	fd->fd_rdir = rootvnode;
	vref(rootvnode);
	fd->fd_jdir = rootvnode;
	vref(rootvnode);
	fd->fd_cdir = rootvnode;
	vref(rootvnode);
	FILEDESC_XUNLOCK(fdp);

You should not do this from a callout routine or interrupt handler however.  
You could do this via a TASK to a private taskqueue with a dedicated kernel 
process however.  (i.e. queue a task that does the above during after 
creating the taskqueue and then queue a task to create the file later).

-- 
John Baldwin


More information about the freebsd-drivers mailing list