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