Subject: LKM puzzle
To: None <tech-kern@netbsd.org>
From: Chris Huang <chris@bsdz.org>
List: tech-kern
Date: 08/02/2001 18:12:32
Hi there,
Recently, I have played around with the LKM stuff on i386 NetBSD1.5, and
it has been interesting. I did get my pseudo driver to work with LKM.
Nevertheless, I am kinda lost now on how LKM handle some of the stuff.
When I first started out writing the character device module, I did not know
that
LKM will automatically save the old content in the cdevsw[] slots to
lkm_olddev,
so by following the examples in /usr/share/lkm/misc, I put the following in
my code
in my loading function where I tried to save the old content manually.
-----cut---------
/* get the first empty cdev_lkm_dummy slot in cdevsw */
/* for ( counter = 0; counter < nchrdev ; counter++)
{
if ( cdevsw[counter].d_open == (dev_type_open((*)))lkmenodev)
{
args->lkm_offset = counter;
break;
}
}
if ( counter == nchrdev )
{
printf("the slots are full !\n");
return(2);
}
/* if we make it here, an empty lkm slot has been found */
/* save the old device driver switch entry */
bcopy(&cdevsw[args->lkm_offset], &oldDevsw, sizeof(struct cdevsw) );
/* load the new device driver switch entry */
bcopy(&dateDevsw, &cdevsw[args->lkm_offset], sizeof(struct cdevsw) );
----cut------
and In my unload function call , I have
---cut ----
bcopy(&oldDevsw, &cdevsw[args->lkm_offset], sizeof(struct cdevsw) );
-----cut-----
my question is that the lkm code help to save the old content in the
cdevsw[]
after the load fucntion is call and restore it after the unload fnction
call. so what I
did to cdevsw[] in my load/unload function shouldn't have any side effect on
cdevsw[]
since LKM code will restore it.
but as I run my code for couple times, the cdevsw[] slot is not restored to
it original
condition, everytime the cdevsw[] slot is different and the one previously
used is never free
up, thus at the end, it couldnt find any free cdev_lkm_dummmy() slots.
Any suggestions why this is happening ?
it will greatly appreciated.
thanks
Chris
-----the following is the complete LKM module code I have
wrote -----------------------
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/exec.h>
#include <sys/lkm.h>
#include <sys/errno.h>
/* Supported driver operations (dev_date.c) */
extern int dateopen();
extern int dateclose();
extern int dateioctl();
/* Number of entries in cdevsw (sys/systm.h) */
extern int nchrdev;
/* based on cdev__oci_init definition (sys/conf.h) */
/* build our own device switch entry table */
static struct cdevsw dateDevsw = {
dateopen,
dateclose,
(dev_type_read((*))) enodev,
(dev_type_write((*))) enodev,
dateioctl,
(dev_type_stop((*))) enodev,
0,
(dev_type_poll((*))) enodev,
(dev_type_mmap((*))) enodev
/* the d_type is ignored */
};
/* store any old device driver switch entry for cleanup when we unload */
static struct cdevsw oldDevsw;
/* the macro which set up the lkm_dev (see sys/lkm) */
MOD_DEV("dateModule", LM_DT_CHAR, 33, &dateDevsw);
/* this is called when the module is loaded */
static int load_date(lkmtp, cmd)
struct lkm_table *lkmtp;
int cmd;
{
int counter;
struct lkm_dev *args;
args = lkmtp->private.lkm_dev;
/* Don't load twice! (lkmexists() is exported by kern_lkm.c) */
if( lkmexists(lkmtp) )
{
printf("dateModule: the module is already exists !! \n");
return( EEXIST);
}
/* get the first empty cdev_lkm_dummy slot in cdevsw */
/* for ( counter = 0; counter < nchrdev ; counter++)
{
if ( cdevsw[counter].d_open == (dev_type_open((*)))lkmenodev)
{
/* got the slot we want */
args->lkm_offset = counter;
break;
}
}
if ( counter == nchrdev )
{
printf("the slots are full !\n");
return(2);
}
/* if we make it here, an empty lkm slot has been found */
/* save the old device driver switch entry */
bcopy(&cdevsw[args->lkm_offset], &oldDevsw, sizeof(struct cdevsw) );
/* load the new device driver switch entry */
bcopy(&dateDevsw, &cdevsw[args->lkm_offset], sizeof(struct cdevsw) );
}//END load_date
/* this is called when the module is unloaded */
static int unload_date(lkmtp, cmd)
struct lkm_table *lkmtp;
int cmd;
{
struct lkm_dev *args;
args = lkmtp->private.lkm_dev;
/* restore the current slot in cdevsw with its original content */
bcopy(&oldDevsw, &cdevsw[args->lkm_offset], sizeof(struct cdevsw) );
}//END unload_date
/* the entry point for the module */
int dateModule(lkmtp, cmd, ver)
struct lkm_table *lkmtp;
int cmd, ver;
{
/* marco from sys/lkm */
DISPATCH(lkmtp, cmd, ver, load_date, unload_date, lkm_nofunc)
}//END dateModule