summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Unangst <tedu@cvs.openbsd.org>2004-03-03 06:26:23 +0000
committerTed Unangst <tedu@cvs.openbsd.org>2004-03-03 06:26:23 +0000
commit378e258203b9bea61402c92b33a681a669dc3840 (patch)
treeaba188b90ac57e861031ca65e914accc28838026
parent22c8f1d4174977fa80e4ae9dc6a31e0cad1d4726 (diff)
better way of finding and identifying lkms.
adapted from pr2910 by peter werner, minus lkmfree removals since i couldn't tell what issue they were fixing.
-rw-r--r--sys/kern/kern_lkm.c60
1 files changed, 42 insertions, 18 deletions
diff --git a/sys/kern/kern_lkm.c b/sys/kern/kern_lkm.c
index c6ee557a414..3e79cb474a2 100644
--- a/sys/kern/kern_lkm.c
+++ b/sys/kern/kern_lkm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_lkm.c,v 1.40 2003/08/23 20:27:30 tedu Exp $ */
+/* $OpenBSD: kern_lkm.c,v 1.41 2004/03/03 06:26:22 tedu Exp $ */
/* $NetBSD: kern_lkm.c,v 1.31 1996/03/31 21:40:27 christos Exp $ */
/*
@@ -69,6 +69,7 @@
/* flags */
#define LKM_ALLOC 0x01
#define LKM_WANT 0x02
+#define LKM_INIT 0x04
#define LKMS_IDLE 0x00
#define LKMS_RESERVED 0x01
@@ -80,9 +81,8 @@
static int lkm_v = 0;
static int lkm_state = LKMS_IDLE;
-static TAILQ_HEAD(, lkm_table) lkmods; /* table of loaded modules */
+static TAILQ_HEAD(lkmods, lkm_table) lkmods; /* table of loaded modules */
static struct lkm_table *curp; /* global for in-progress ops */
-static size_t nlkms = 0; /* number of loaded lkms */
static struct lkm_table *lkmalloc(void);
static void lkmfree(struct lkm_table *);
@@ -103,6 +103,7 @@ lkminit()
{
TAILQ_INIT(&lkmods);
+ lkm_v |= LKM_INIT;
}
/*ARGSUSED*/
@@ -114,6 +115,9 @@ lkmopen(dev_t dev, int flag, int devtype, struct proc *p)
if (minor(dev) != 0)
return (ENXIO);
+ if (!(lkm_v & LKM_INIT))
+ lkminit();
+
/*
* Use of the loadable kernel module device must be exclusive; we
* may try to remove this restriction later, but it's really no
@@ -133,9 +137,6 @@ lkmopen(dev_t dev, int flag, int devtype, struct proc *p)
}
lkm_v |= LKM_ALLOC;
- if (nlkms == 0)
- lkminit(); /* XXX */
-
return (0); /* pseudo-device open */
}
@@ -147,13 +148,28 @@ lkmopen(dev_t dev, int flag, int devtype, struct proc *p)
static struct lkm_table *
lkmalloc()
{
- struct lkm_table *ret = NULL;
+ struct lkm_table *p, *ret = NULL;
+ int id = 0;
MALLOC(ret, struct lkm_table *, sizeof(*ret), M_DEVBUF, M_WAITOK);
ret->refcnt = ret->depcnt = 0;
- ret->id = nlkms++;
ret->sym_id = -1;
- TAILQ_INSERT_TAIL(&lkmods, ret, list);
+ /*
+ * walk the list finding the first free id. as long as the list is
+ * kept sorted this is not too ineffcient, which is why we insert in
+ * order below.
+ */
+ TAILQ_FOREACH(p, &lkmods, list) {
+ if (id == p->id)
+ id++;
+ else
+ break;
+ }
+ ret->id = id;
+ if (p == NULL) /* either first or last entry */
+ TAILQ_INSERT_TAIL(&lkmods, ret, list);
+ else
+ TAILQ_INSERT_BEFORE(p, ret, list);
return ret;
}
@@ -168,7 +184,6 @@ lkmfree(struct lkm_table *p)
TAILQ_REMOVE(&lkmods, p, list);
free(p, M_DEVBUF);
curp = NULL;
- nlkms--;
}
struct lkm_table *
@@ -188,6 +203,18 @@ lkmlookup(int i, char *name, int *error)
{
struct lkm_table *p = NULL;
char istr[MAXLKMNAME];
+
+ /*
+ * p being NULL here implies the list is empty, so any lookup is
+ * invalid (name based or otherwise). Since the list of modules is
+ * kept sorted by id, lowest to highest, the id of the last entry
+ * will be the highest in use.
+ */
+ p = TAILQ_LAST(&lkmods, lkmods);
+ if (p == NULL || i > p->id) {
+ *error = EINVAL;
+ return NULL;
+ }
if (i < 0) { /* unload by name */
/*
@@ -203,14 +230,11 @@ lkmlookup(int i, char *name, int *error)
if (!strcmp(istr, p->private.lkm_any->lkm_name))
break;
}
- } else if (i >= nlkms) {
- *error = EINVAL;
- return NULL;
- } else
- for (p = TAILQ_FIRST(&lkmods); p != NULL && i--;
- p = TAILQ_NEXT(p, list))
- ;
-
+ } else
+ TAILQ_FOREACH(p, &lkmods, list)
+ if (i == p->id)
+ break;
+
if (p == NULL)
*error = ENOENT;