summaryrefslogtreecommitdiff
path: root/sys/kern/kern_lkm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/kern_lkm.c')
-rw-r--r--sys/kern/kern_lkm.c209
1 files changed, 160 insertions, 49 deletions
diff --git a/sys/kern/kern_lkm.c b/sys/kern/kern_lkm.c
index e5ea6297398d..f7ca01d4b4a2 100644
--- a/sys/kern/kern_lkm.c
+++ b/sys/kern/kern_lkm.c
@@ -30,10 +30,11 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: kern_lkm.c,v 1.59 1998/11/10 09:12:40 peter Exp $
+ * $Id: kern_lkm.c,v 1.56 1998/09/07 05:42:15 bde Exp $
*/
#include "opt_devfs.h"
+#include "opt_no_lkm.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -78,6 +79,16 @@ static int lkm_state = LKMS_IDLE;
static struct lkm_table lkmods[MAXLKMS]; /* table of loaded modules */
static struct lkm_table *curp; /* global for in-progress ops */
+/*
+ * XXX this bloat just exands the sysctl__vfs linker set a little so that
+ * we can attach sysctls for VFS LKMs without expanding the linker set.
+ * Currently (1998/09/06), only one VFS uses sysctls, so 2 extra linker
+ * set slots are more than sufficient.
+ */
+extern struct linker_set sysctl__vfs;
+SYSCTL_INT(_vfs, OID_AUTO, lkm0, CTLFLAG_RD, &lkm_v, 0, "");
+SYSCTL_INT(_vfs, OID_AUTO, lkm1, CTLFLAG_RD, &lkm_v, 0, "");
+
static int _lkm_dev __P((struct lkm_table *lkmtp, int cmd));
static int _lkm_exec __P((struct lkm_table *lkmtp, int cmd));
static int _lkm_vfs __P((struct lkm_table *lkmtp, int cmd));
@@ -239,7 +250,7 @@ lkmcioctl(dev, cmd, data, flag, p)
#ifdef DEBUG
printf("LKM: LMRESERV (actual = 0x%08lx)\n", curp->area);
- printf("LKM: LMRESERV (adjusted = 0x%08lx)\n",
+ printf("LKM: LMRESERV (adjusted = 0x%08x)\n",
trunc_page(curp->area));
#endif /* DEBUG */
lkm_state = LKMS_RESERVED;
@@ -480,6 +491,21 @@ lkmcioctl(dev, cmd, data, flag, p)
return (err);
}
+/*
+ * Acts like "nosys" but can be identified in sysent for dynamic call
+ * number assignment for a limited number of calls.
+ *
+ * Place holder for system call slots reserved for loadable modules.
+ */
+int
+lkmnosys(p, args)
+ struct proc *p;
+ struct nosys_args *args;
+{
+
+ return(nosys(p, args));
+}
+
int
lkmexists(lkmtp)
struct lkm_table *lkmtp;
@@ -522,16 +548,35 @@ _lkm_syscall(lkmtp, cmd)
/* don't load twice! */
if (lkmexists(lkmtp))
return(EEXIST);
+ if ((i = args->lkm_offset) == LKM_ANON) { /* auto */
+ /*
+ * Search the table looking for a slot...
+ */
+ for (i = 0; i < aout_sysvec.sv_size; i++)
+ if (aout_sysvec.sv_table[i].sy_call ==
+ (sy_call_t *)lkmnosys)
+ break; /* found it! */
+ /* out of allocable slots? */
+ if (i == aout_sysvec.sv_size) {
+ err = ENFILE;
+ break;
+ }
+ } else { /* assign */
+ if (i < 0 || i >= aout_sysvec.sv_size) {
+ err = EINVAL;
+ break;
+ }
+ }
- if (args->lkm_offset == LKM_ANON)
- i = NO_SYSCALL;
- else
- i = args->lkm_offset;
+ /* save old */
+ bcopy(&aout_sysvec.sv_table[i],
+ &(args->lkm_oldent),
+ sizeof(struct sysent));
- err = syscall_register(&i, args->lkm_sysent,
- &(args->lkm_oldent));
- if (err)
- return(err);
+ /* replace with new */
+ bcopy(args->lkm_sysent,
+ &aout_sysvec.sv_table[i],
+ sizeof(struct sysent));
/* done! */
args->lkm_offset = i; /* slot in sysent[] */
@@ -542,9 +587,11 @@ _lkm_syscall(lkmtp, cmd)
/* current slot... */
i = args->lkm_offset;
- err = syscall_deregister(&i, &(args->lkm_oldent));
- if (err)
- return(err);
+ /* replace current slot contents with old contents */
+ bcopy(&(args->lkm_oldent),
+ &aout_sysvec.sv_table[i],
+ sizeof(struct sysent));
+
break;
case LKM_E_STAT: /* no special handling... */
@@ -564,8 +611,11 @@ _lkm_vfs(lkmtp, cmd)
int cmd;
{
struct lkm_vfs *args = lkmtp->private.lkm_vfs;
+ struct linker_set *l;
+ struct sysctl_oid **oidpp;
struct vfsconf *vfc = args->lkm_vfsconf;
- int error, i;
+ struct vfsconf *vfsp, *prev_vfsp;
+ int error, i, maxtypenum;
switch(cmd) {
case LKM_E_LOAD:
@@ -573,13 +623,47 @@ _lkm_vfs(lkmtp, cmd)
if (lkmexists(lkmtp))
return(EEXIST);
- for(i = 0; args->lkm_vnodeops->ls_items[i]; i++)
- vfs_add_vnodeops((void*)args->lkm_vnodeops->ls_items[i]);
- error = vfs_register(vfc);
- if (error)
- return(error);
+ for (vfsp = vfsconf; vfsp->vfc_next; vfsp = vfsp->vfc_next) {
+ if (!strcmp(vfc->vfc_name, vfsp->vfc_name)) {
+ return EEXIST;
+ }
+ }
- args->lkm_offset = vfc->vfc_typenum;
+ args->lkm_offset = vfc->vfc_typenum = maxvfsconf++;
+ if (vfc->vfc_vfsops->vfs_oid != NULL) {
+ l = &sysctl__vfs;
+ for (i = l->ls_length,
+ oidpp = (struct sysctl_oid **)l->ls_items;
+ i--; oidpp++) {
+ if (!*oidpp || *oidpp == &sysctl___vfs_lkm0 ||
+ *oidpp == &sysctl___vfs_lkm1) {
+ *oidpp = vfc->vfc_vfsops->vfs_oid;
+ (*oidpp)->oid_number = vfc->vfc_typenum;
+ sysctl_order_all();
+ break;
+ }
+ }
+ }
+
+ vfsp->vfc_next = vfc;
+ vfc->vfc_next = NULL;
+
+ /* like in vfs_op_init */
+ for(i = 0; args->lkm_vnodeops->ls_items[i]; i++) {
+ struct vnodeopv_desc *opv = (struct vnodeopv_desc *)
+ args->lkm_vnodeops->ls_items[i];
+ *(opv->opv_desc_vector_p) = NULL;
+ }
+ for(i = 0; args->lkm_vnodeops->ls_items[i]; i++) {
+ struct vnodeopv_desc *opv = (struct vnodeopv_desc *)
+ args->lkm_vnodeops->ls_items[i];
+ vfs_opv_init(opv);
+ }
+
+ /*
+ * Call init function for this VFS...
+ */
+ (*(vfc->vfc_vfsops->vfs_init))(vfc);
/* done! */
break;
@@ -588,12 +672,49 @@ _lkm_vfs(lkmtp, cmd)
/* current slot... */
i = args->lkm_offset;
- error = vfs_unregister(vfc);
- if (error)
- return(error);
+ prev_vfsp = NULL;
+ for (vfsp = vfsconf; vfsp;
+ prev_vfsp = vfsp, vfsp = vfsp->vfc_next) {
+ if (!strcmp(vfc->vfc_name, vfsp->vfc_name))
+ break;
+ }
+ if (vfsp == NULL) {
+ return EINVAL;
+ }
+
+ if (vfsp->vfc_refcount) {
+ return EBUSY;
+ }
+
+ if (vfc->vfc_vfsops->vfs_uninit != NULL) {
+ error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp);
+ if (error)
+ return (error);
+ }
+
+ prev_vfsp->vfc_next = vfsp->vfc_next;
+
+ if (vfsp->vfc_vfsops->vfs_oid != NULL) {
+ l = &sysctl__vfs;
+ for (i = l->ls_length,
+ oidpp = (struct sysctl_oid **)l->ls_items;
+ i--; oidpp++) {
+ if (*oidpp == vfsp->vfc_vfsops->vfs_oid) {
+ *oidpp = NULL;
+ sysctl_order_all();
+ break;
+ }
+ }
+ }
- for(i = 0; args->lkm_vnodeops->ls_items[i]; i++)
- vfs_rm_vnodeops((void*)args->lkm_vnodeops->ls_items[i]);
+ /*
+ * Maintain maxvfsconf.
+ */
+ maxtypenum = 0;
+ for (vfsp = vfsconf; vfsp != NULL; vfsp = vfsp->vfc_next)
+ if (maxtypenum < vfsp->vfc_typenum)
+ maxtypenum = vfsp->vfc_typenum;
+ maxvfsconf = maxtypenum + 1;
break;
@@ -707,7 +828,10 @@ _lkm_exec(lkmtp, cmd)
int cmd;
{
struct lkm_exec *args = lkmtp->private.lkm_exec;
+ int i;
int err = 0;
+ const struct execsw **execsw =
+ (const struct execsw **)&execsw_set.ls_items[0];
switch(cmd) {
case LKM_E_LOAD:
@@ -722,7 +846,7 @@ _lkm_exec(lkmtp, cmd)
err = exec_register(args->lkm_exec);
/* done! */
- args->lkm_offset = 0;
+ args->lkm_offset = 0; /* slot in execsw[] */
break;
@@ -799,40 +923,27 @@ lkm_nullcmd(lkmtp, cmd)
return (0);
}
+static lkm_devsw_installed = 0;
#ifdef DEVFS
static void *lkmc_devfs_token;
#endif
-static int
-lkm_modevent(module_t mod, int type, void *data)
+static void lkm_drvinit(void *unused)
{
dev_t dev;
- static struct cdevsw *oldcdevsw;
- switch (type) {
- case MOD_LOAD:
+ if( ! lkm_devsw_installed ) {
dev = makedev(CDEV_MAJOR, 0);
- cdevsw_add(&dev, &lkmc_cdevsw, &oldcdevsw);
+ cdevsw_add(&dev,&lkmc_cdevsw, NULL);
+ lkm_devsw_installed = 1;
#ifdef DEVFS
lkmc_devfs_token = devfs_add_devswf(&lkmc_cdevsw, 0, DV_CHR,
UID_ROOT, GID_WHEEL, 0644,
"lkm");
#endif
- break;
- case MOD_UNLOAD:
-#ifdef DEVFS
- devfs_remove_dev(lkmc_devfs_token);
-#endif
- cdevsw_add(&dev, oldcdevsw, NULL);
- break;
- default:
- break;
- }
- return 0;
+ }
}
-static moduledata_t lkm_mod = {
- "lkm",
- lkm_modevent,
- NULL
-};
-DECLARE_MODULE(lkm, lkm_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+CDEV_MAJOR);
+
+#ifndef NO_LKM
+SYSINIT(lkmdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,lkm_drvinit,NULL)
+#endif