| Summary: | kldload() panics if error code is returned from <module_name>_load(). | ||
|---|---|---|---|
| Product: | Base System | Reporter: | jtrainor <jtrainor> |
| Component: | kern | Assignee: | freebsd-bugs (Nobody) <bugs> |
| Status: | Closed FIXED | ||
| Severity: | Affects Only Me | ||
| Priority: | Normal | ||
| Version: | 4.2-RELEASE | ||
| Hardware: | Any | ||
| OS: | Any | ||
jtrainor@fastekintl.com wrote: > > >Number: 26034 > >Category: kern > >Synopsis: kldload() panics if error code is returned from <module_name >_load(). > >Description: > panic trap 12 (page fault) in kldload while attempting to return an error fro m <module_name>_load. If I set the return value prior to entering the case statement, proper behavior is observed. If I set the return value inside the case statement, panic occurs. See code below. This is because if you fail on the MOD_LOAD case, the linker calls all the MOD_UNLOADs for the modules in the kld file. In your case, you are calling "destroy_dev(sdev);" on MOD_UNLOAD, which is panicing since sdev is uninitialized. This is actually a bug in your module due to the existing module load/unload semantics. Remember, there can be more than one module inside a .ko kld file. One could argue that a MOD_UNLOAD event should be skipped for modules that have failed to load successfully.. I think this change needs to happen. Cheers, -Peter -- Peter Wemm - peter@FreeBSD.org; peter@yahoo-inc.com; peter@netplex.com.au "All of this is for nothing if we don't go to the stars" - JMS/B5 State Changed From-To: open->closed Problem appears to be in the sample code. |
panic trap 12 (page fault) in kldload while attempting to return an error from <module_name>_load. If I set the return value prior to entering the case statement, proper behavior is observed. If I set the return value inside the case statement, panic occurs. See code below. How-To-Repeat: /* =============================================================== */ /* Program..... KLD Character Device Implementation Skeleton */ /* Version..... 1.0 */ /* File........ CDEVEXAM.C */ /* Date........ 03/04/2001 */ /* Programmer.. Jim Trainor */ /* Copyright (c)2001 Fastek International Ltd. */ /* --------------------------------------------------------------- */ /* */ /* --------------------------------------------------------------- */ /* This code is from the article "Dynamic Kernel Linker (KLD) */ /* Facility Programming Tutorial" by Andrew Reiter. The article */ /* was in "daemonnews" October 2000. */ /* The module is loaded with "kldload ./cdev_exam.ko" */ /* --------------------------------------------------------------- */ /* $Header$ */ /* --------------------------------------------------------------- */ /* <revision comments in the form> */ /* mm/dd/yyyy - pid - comment */ /* =============================================================== */ #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/uio.h> #include <sys/conf.h> /* for macro DEV_MODULE */ /* --------------------------------------------------------------- */ /* Device access function declarations */ /* --------------------------------------------------------------- */ int example_open(dev_t dev, int oflags, int devtype, struct proc *p); int example_close(dev_t dev, int fflag, int devtype, struct proc *p); int example_read(dev_t dev, struct uio *uio, int ioflag); int example_write(dev_t dev, struct uio *uio, int ioflag); /* --------------------------------------------------------------- */ /* Define global variables. */ /* --------------------------------------------------------------- */ /* Stores string recv'd by _write() */ static char buf[512+1]; static int len; /* * Used as the variable that is the reference to our device * in devfs... we must keep this variable sane until we * call kldunload. */ static dev_t sdev; /* --------------------------------------------------------------- */ /* File operations supported by our device driver */ /* --------------------------------------------------------------- */ static struct cdevsw example_cdevsw = { example_open, example_close, example_read, example_write, noioctl, nopoll, nommap, nostrategy, "example", 34, /* /usr/src/sys/conf/majors */ nodump, nopsize, D_TTY, -1 }; /* --------------------------------------------------------------- */ /* chardev_example_load() */ /* */ /* This is used as the function that handles what is to occur */ /* when the KLD binary is loaded and unloaded via the kldload */ /* and kldunload programs. */ /* --------------------------------------------------------------- */ static int chardev_example_load(struct module *m, int what, void *arg) { int err = 0; /* Test load failure case 1 - before case */ /* err = EINVAL; */ if(!err) { switch (what) { case MOD_LOAD: /* kldload */ /* Test load failure case 2 - inside case */ err = EINVAL; if(!err) { sdev = make_dev(&example_cdevsw, /* explained below */ 0, UID_ROOT, GID_WHEEL, 0600, "example"); printf("Example device loaded.\n"); } break; case MOD_UNLOAD: destroy_dev(sdev); /* explained below */ printf("Example device unloaded.\n"); break; default: err = EINVAL; break; } } return(err); } /* --------------------------------------------------------------- */ /* example_open() */ /* */ /* This open function solely checks for open(2) flags. We are only */ /* allowing for the flags to be O_RDWR for the purpose of showing */ /* how one could only allow a read-only device, for example. */ /* --------------------------------------------------------------- */ int example_open(dev_t dev, int oflags, int devtype, struct proc *p) { int err = 0; memset(&buf, '\0', 513); len = 0; uprintf("Opened device \"example\" successfully.\n"); return(err); } /* --------------------------------------------------------------- */ /* example_close() */ /* */ /* Simply "closes" our device that was opened with example_open. */ /* --------------------------------------------------------------- */ int example_close(dev_t dev, int fflag, int devtype, struct proc *p) { memset(&buf, '\0', 513); len = 0; uprintf("Closing device \"example.\"\n"); return(0); } /* --------------------------------------------------------------- */ /* example_write() */ /* */ /* The read function just takes the buf that was saved */ /* via example_write() and returns it to userland for */ /* accessing. */ /* --------------------------------------------------------------- */ int example_read(dev_t dev, struct uio *uio, int ioflag) { int err = 0; if (len <= 0) { err = -1; } else {/* copy buf to userland */ err = copystr(&buf, uio->uio_iov->iov_base, 513, &len); } return(err); } /* --------------------------------------------------------------- */ /* example_write() */ /* */ /* example_write takes in a character string and saves it to buf */ /* for later accessing. */ /* --------------------------------------------------------------- */ int example_write(dev_t dev, struct uio *uio, int ioflag) { int err = 0; err = copyinstr(uio->uio_iov->iov_base, &buf, 512, &len); if (err != 0) { uprintf("Write to \"example\" failed.\n"); } return(err); } DEV_MODULE(chardev_example, chardev_example_load, NULL);