summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2015-05-21 06:30:44 +0000
committerhselasky <hselasky@FreeBSD.org>2015-05-21 06:30:44 +0000
commite136fd019b14c4cac4794e97f3304d39a7e87584 (patch)
treeacd66e168b16d83cdcb639c8c9695453b38ed01f /sys
parentf1d984d9772f5088101612e037ca301af111523a (diff)
downloadFreeBSD-src-e136fd019b14c4cac4794e97f3304d39a7e87584.zip
FreeBSD-src-e136fd019b14c4cac4794e97f3304d39a7e87584.tar.gz
MFC r280495:
Implement a simple OID number garbage collector. Given the increasing number of dynamically created and destroyed SYSCTLs during runtime it is very likely that the current new OID number limit of 0x7fffffff can be reached. Especially if dynamic OID creation and destruction results from automatic tests. Additional changes: - Optimize the typical use case by decrementing the next automatic OID sequence number instead of incrementing it. This saves searching time when inserting new OIDs into a fresh parent OID node. - Add simple check for duplicate non-automatic OID numbers.
Diffstat (limited to 'sys')
-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 fec4aea..ddc3369 100644
--- a/sys/kern/kern_sysctl.c
+++ b/sys/kern/kern_sysctl.c
@@ -142,6 +142,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
@@ -158,37 +160,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);
OpenPOWER on IntegriCloud