aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Petter Selasky <hselasky@FreeBSD.org>2015-03-25 08:55:34 +0000
committerHans Petter Selasky <hselasky@FreeBSD.org>2015-03-25 08:55:34 +0000
commit38668c604435bbbb2e0921d758c5c14fb2c4495a (patch)
tree151dc180c05598539a5705583b43dab4e4a5770a
parent8c35e0d9aac976211dc2b0ab3250fceccc144554 (diff)
Notes
-rw-r--r--sys/kern/kern_sysctl.c63
1 files changed, 47 insertions, 16 deletions
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c
index f33184868089..61e63001f52a 100644
--- a/sys/kern/kern_sysctl.c
+++ b/sys/kern/kern_sysctl.c
@@ -296,6 +296,8 @@ sysctl_register_oid(struct sysctl_oid *oidp)
struct sysctl_oid_list *parent = oidp->oid_parent;
struct sysctl_oid *p;
struct sysctl_oid *q;
+ int oid_number;
+ int timeout = 2;
/*
* First check if another oid with the same name already
@@ -312,37 +314,66 @@ sysctl_register_oid(struct sysctl_oid *oidp)
return;
}
}
+ /* get current OID number */
+ oid_number = oidp->oid_number;
+
+#if (OID_AUTO >= 0)
+#error "OID_AUTO is expected to be a negative value"
+#endif
/*
- * If this oid has a number OID_AUTO, give it a number which
- * is greater than any current oid.
+ * Any negative OID number qualifies as OID_AUTO. Valid OID
+ * numbers should always be positive.
+ *
* NOTE: DO NOT change the starting value here, change it in
* <sys/sysctl.h>, and make sure it is at least 256 to
* accomodate e.g. net.inet.raw as a static sysctl node.
*/
- if (oidp->oid_number == OID_AUTO) {
- static int newoid = CTL_AUTO_START;
+ if (oid_number < 0) {
+ static int newoid;
- oidp->oid_number = newoid++;
- if (newoid == 0x7fffffff)
- panic("out of oids");
- }
-#if 0
- else if (oidp->oid_number >= CTL_AUTO_START) {
- /* do not panic; this happens when unregistering sysctl sets */
- printf("static sysctl oid too high: %d", oidp->oid_number);
+ /*
+ * By decrementing the next OID number we spend less
+ * time inserting the OIDs into a sorted list.
+ */
+ if (--newoid < CTL_AUTO_START)
+ newoid = 0x7fffffff;
+
+ oid_number = newoid;
}
-#endif
/*
- * Insert the oid into the parent's list in order.
+ * Insert the OID into the parent's list sorted by OID number.
*/
+retry:
q = NULL;
SLIST_FOREACH(p, parent, oid_link) {
- if (oidp->oid_number < p->oid_number)
+ /* check if the current OID number is in use */
+ if (oid_number == p->oid_number) {
+ /* get the next valid OID number */
+ if (oid_number < CTL_AUTO_START ||
+ oid_number == 0x7fffffff) {
+ /* wraparound - restart */
+ oid_number = CTL_AUTO_START;
+ /* don't loop forever */
+ if (!timeout--)
+ panic("sysctl: Out of OID numbers\n");
+ goto retry;
+ } else {
+ oid_number++;
+ }
+ } else if (oid_number < p->oid_number)
break;
q = p;
}
- if (q)
+ /* check for non-auto OID number collision */
+ if (oidp->oid_number >= 0 && oidp->oid_number < CTL_AUTO_START &&
+ oid_number >= CTL_AUTO_START) {
+ printf("sysctl: OID number(%d) is already in use for '%s'\n",
+ oidp->oid_number, oidp->oid_name);
+ }
+ /* update the OID number, if any */
+ oidp->oid_number = oid_number;
+ if (q != NULL)
SLIST_INSERT_AFTER(q, oidp, oid_link);
else
SLIST_INSERT_HEAD(parent, oidp, oid_link);