diff --git a/sys/compat/linuxkpi/common/include/linux/sysfs.h b/sys/compat/linuxkpi/common/include/linux/sysfs.h --- a/sys/compat/linuxkpi/common/include/linux/sysfs.h +++ b/sys/compat/linuxkpi/common/include/linux/sysfs.h @@ -246,7 +246,7 @@ struct attribute **attr; struct sysctl_oid *oidp; - SLIST_FOREACH(oidp, SYSCTL_CHILDREN(kobj->oidp), oid_link) { + SPLAY_FOREACH(oidp, sysctl_oid_list, SYSCTL_CHILDREN(kobj->oidp)) { if (strcmp(oidp->oid_name, grp->name) != 0) continue; for (attr = grp->attrs; *attr != NULL; attr++) { diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -59,7 +59,6 @@ #include #include #include -#include #include #include #include @@ -84,6 +83,8 @@ static MALLOC_DEFINE(M_SYSCTLOID, "sysctloid", "sysctl dynamic oids"); static MALLOC_DEFINE(M_SYSCTLTMP, "sysctltmp", "sysctl temp output buffer"); +SPLAY_GENERATE(sysctl_oid_list, sysctl_oid, oid_link, cmp_splay_oid); + /* * The sysctllock protects the MIB tree. It also protects sysctl * contexts used with dynamic sysctls. The sysctl_register_oid() and @@ -100,27 +101,26 @@ * The sysctlstringlock is used to protect concurrent access to writable * string nodes in sysctl_handle_string(). */ -static struct rmlock sysctllock; +/* Even though we never lock it for reading, sysctllock needs to be an sx lock + * instead of a mutex to support sleeping. + */ +static struct sx sysctllock; static struct sx __exclusive_cache_line sysctlmemlock; static struct sx sysctlstringlock; -#define SYSCTL_WLOCK() rm_wlock(&sysctllock) -#define SYSCTL_WUNLOCK() rm_wunlock(&sysctllock) -#define SYSCTL_RLOCK(tracker) rm_rlock(&sysctllock, (tracker)) -#define SYSCTL_RUNLOCK(tracker) rm_runlock(&sysctllock, (tracker)) -#define SYSCTL_WLOCKED() rm_wowned(&sysctllock) -#define SYSCTL_ASSERT_LOCKED() rm_assert(&sysctllock, RA_LOCKED) -#define SYSCTL_ASSERT_WLOCKED() rm_assert(&sysctllock, RA_WLOCKED) -#define SYSCTL_ASSERT_RLOCKED() rm_assert(&sysctllock, RA_RLOCKED) -#define SYSCTL_INIT() rm_init_flags(&sysctllock, "sysctl lock", \ - RM_SLEEPABLE) +#define SYSCTL_LOCK() sx_xlock(&sysctllock) +#define SYSCTL_UNLOCK() sx_xunlock(&sysctllock) +#define SYSCTL_RLOCK(tracker) sx_xlock(&sysctllock) +#define SYSCTL_RUNLOCK(tracker) sx_xunlock(&sysctllock) +#define SYSCTL_ASSERT_LOCKED() sx_assert(&sysctllock, SA_XLOCKED) +#define SYSCTL_INIT() sx_init(&sysctllock, "sysctl lock") #define SYSCTL_SLEEP(ch, wmesg, timo) \ - rm_sleep(ch, &sysctllock, 0, wmesg, timo) + sx_sleep(ch, &sysctllock, 0, wmesg, timo) static int sysctl_root(SYSCTL_HANDLER_ARGS); /* Root list */ -struct sysctl_oid_list sysctl__children = SLIST_HEAD_INITIALIZER(&sysctl__children); +struct sysctl_oid_list sysctl__children = SPLAY_INITIALIZER(&sysctl__children); static char* sysctl_escape_name(const char*); static int sysctl_remove_oid_locked(struct sysctl_oid *oidp, int del, @@ -134,7 +134,7 @@ struct sysctl_oid *oidp; SYSCTL_ASSERT_LOCKED(); - SLIST_FOREACH(oidp, list, oid_link) { + SPLAY_FOREACH(oidp, sysctl_oid_list, list) { if (strcmp(oidp->oid_name, name) == 0) { return (oidp); } @@ -151,29 +151,26 @@ sysctl_wlock(void) { - SYSCTL_WLOCK(); + SYSCTL_LOCK(); } void sysctl_wunlock(void) { - SYSCTL_WUNLOCK(); + SYSCTL_UNLOCK(); } static int sysctl_root_handler_locked(struct sysctl_oid *oid, void *arg1, intmax_t arg2, - struct sysctl_req *req, struct rm_priotracker *tracker) + struct sysctl_req *req) { int error; if (oid->oid_kind & CTLFLAG_DYN) atomic_add_int(&oid->oid_running, 1); - if (tracker != NULL) - SYSCTL_RUNLOCK(tracker); - else - SYSCTL_WUNLOCK(); + SYSCTL_UNLOCK(); /* * Treat set CTLFLAG_NEEDGIANT and unset CTLFLAG_MPSAFE flags the same, @@ -189,10 +186,7 @@ KFAIL_POINT_ERROR(_debug_fail_point, sysctl_running, error); - if (tracker != NULL) - SYSCTL_RLOCK(tracker); - else - SYSCTL_WLOCK(); + SYSCTL_LOCK(); if (oid->oid_kind & CTLFLAG_DYN) { if (atomic_fetchadd_int(&oid->oid_running, -1) == 1 && @@ -335,7 +329,7 @@ return; } error = sysctl_root_handler_locked(oidp, oidp->oid_arg1, - oidp->oid_arg2, &req, NULL); + oidp->oid_arg2, &req); if (error != 0) printf("Setting sysctl %s failed: %d\n", path + rem, error); if (penv != NULL) @@ -356,11 +350,14 @@ indx = 0; while (indx < CTL_MAXNAME && indx >= 0) { if (nodes[indx] == NULL && indx == 0) - nodes[indx] = SLIST_FIRST(&sysctl__children); + nodes[indx] = SPLAY_MIN(sysctl_oid_list, + &sysctl__children); else if (nodes[indx] == NULL) - nodes[indx] = SLIST_FIRST(&nodes[indx - 1]->oid_children); + nodes[indx] = SPLAY_MIN(sysctl_oid_list, + &nodes[indx - 1]->oid_children); else - nodes[indx] = SLIST_NEXT(nodes[indx], oid_link); + nodes[indx] = SPLAY_NEXT(sysctl_oid_list, + &nodes[indx - 1]->oid_children, nodes[indx]); if (nodes[indx] == needle) return (indx + 1); @@ -409,11 +406,9 @@ static int sysctl_reuse_test(SYSCTL_HANDLER_ARGS) { - struct rm_priotracker tracker; - - SYSCTL_RLOCK(&tracker); + SYSCTL_LOCK(); sysctl_warn_reuse(__func__, oidp); - SYSCTL_RUNLOCK(&tracker); + SYSCTL_UNLOCK(); return (0); } SYSCTL_PROC(_sysctl, OID_AUTO, reuse_test, @@ -425,8 +420,7 @@ sysctl_register_oid(struct sysctl_oid *oidp) { struct sysctl_oid_list *parent = oidp->oid_parent; - struct sysctl_oid *p; - struct sysctl_oid *q; + struct sysctl_oid *p, key; int oid_number; int timeout = 2; @@ -434,7 +428,7 @@ * First check if another oid with the same name already * exists in the parent's list. */ - SYSCTL_ASSERT_WLOCKED(); + SYSCTL_ASSERT_LOCKED(); p = sysctl_find_oidname(oidp->oid_name, parent); if (p != NULL) { if ((p->oid_kind & CTLTYPE) == CTLTYPE_NODE) { @@ -476,25 +470,21 @@ * Insert the OID into the parent's list sorted by OID number. */ retry: - q = NULL; - SLIST_FOREACH(p, parent, oid_link) { - /* 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; + key.oid_number = oid_number; + p = SPLAY_FIND(sysctl_oid_list, parent, &key); + if (p) { + /* 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++; + } } /* check for non-auto OID number collision */ if (oidp->oid_number >= 0 && oidp->oid_number < CTL_AUTO_START && @@ -504,10 +494,7 @@ } /* 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); + SPLAY_INSERT(sysctl_oid_list, parent, oidp); if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE && #ifdef VIMAGE @@ -542,7 +529,7 @@ sysctl_enable_oid(struct sysctl_oid *oidp) { - SYSCTL_ASSERT_WLOCKED(); + SYSCTL_ASSERT_LOCKED(); if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) { KASSERT((oidp->oid_kind & CTLFLAG_DORMANT) == 0, ("sysctl node is marked as dormant")); @@ -556,22 +543,15 @@ void sysctl_unregister_oid(struct sysctl_oid *oidp) { - struct sysctl_oid *p; int error; - SYSCTL_ASSERT_WLOCKED(); + SYSCTL_ASSERT_LOCKED(); if (oidp->oid_number == OID_AUTO) { error = EINVAL; } else { error = ENOENT; - SLIST_FOREACH(p, oidp->oid_parent, oid_link) { - if (p == oidp) { - SLIST_REMOVE(oidp->oid_parent, oidp, - sysctl_oid, oid_link); - error = 0; - break; - } - } + if (SPLAY_REMOVE(sysctl_oid_list, oidp->oid_parent, oidp)) + error = 0; } /* @@ -617,7 +597,7 @@ * XXX This algorithm is a hack. But I don't know any * XXX better solution for now... */ - SYSCTL_WLOCK(); + SYSCTL_LOCK(); TAILQ_FOREACH(e, clist, link) { error = sysctl_remove_oid_locked(e->entry, 0, 0); if (error) @@ -637,7 +617,7 @@ e1 = TAILQ_PREV(e1, sysctl_ctx_list, link); } if (error) { - SYSCTL_WUNLOCK(); + SYSCTL_UNLOCK(); return(EBUSY); } /* Now really delete the entries */ @@ -651,7 +631,7 @@ free(e, M_SYSCTLOID); e = e1; } - SYSCTL_WUNLOCK(); + SYSCTL_UNLOCK(); return (error); } @@ -661,7 +641,7 @@ { struct sysctl_ctx_entry *e; - SYSCTL_ASSERT_WLOCKED(); + SYSCTL_ASSERT_LOCKED(); if (clist == NULL || oidp == NULL) return(NULL); e = malloc(sizeof(struct sysctl_ctx_entry), M_SYSCTLOID, M_WAITOK); @@ -676,7 +656,7 @@ { struct sysctl_ctx_entry *e; - SYSCTL_ASSERT_WLOCKED(); + SYSCTL_ASSERT_LOCKED(); if (clist == NULL || oidp == NULL) return(NULL); TAILQ_FOREACH(e, clist, link) { @@ -698,15 +678,15 @@ if (clist == NULL || oidp == NULL) return (EINVAL); - SYSCTL_WLOCK(); + SYSCTL_LOCK(); e = sysctl_ctx_entry_find(clist, oidp); if (e != NULL) { TAILQ_REMOVE(clist, e, link); - SYSCTL_WUNLOCK(); + SYSCTL_UNLOCK(); free(e, M_SYSCTLOID); return (0); } else { - SYSCTL_WUNLOCK(); + SYSCTL_UNLOCK(); return (ENOENT); } } @@ -722,9 +702,9 @@ { int error; - SYSCTL_WLOCK(); + SYSCTL_LOCK(); error = sysctl_remove_oid_locked(oidp, del, recurse); - SYSCTL_WUNLOCK(); + SYSCTL_UNLOCK(); return (error); } @@ -732,18 +712,15 @@ sysctl_remove_name(struct sysctl_oid *parent, const char *name, int del, int recurse) { - struct sysctl_oid *p, *tmp; + struct sysctl_oid *p; int error; error = ENOENT; - SYSCTL_WLOCK(); - SLIST_FOREACH_SAFE(p, SYSCTL_CHILDREN(parent), oid_link, tmp) { - if (strcmp(p->oid_name, name) == 0) { - error = sysctl_remove_oid_locked(p, del, recurse); - break; - } - } - SYSCTL_WUNLOCK(); + SYSCTL_LOCK(); + p = sysctl_find_oidname(name, &parent->oid_children); + if (p) + error = sysctl_remove_oid_locked(p, del, recurse); + SYSCTL_UNLOCK(); return (error); } @@ -794,7 +771,7 @@ struct sysctl_oid *p, *tmp; int error; - SYSCTL_ASSERT_WLOCKED(); + SYSCTL_ASSERT_LOCKED(); if (oidp == NULL) return(EINVAL); if ((oidp->oid_kind & CTLFLAG_DYN) == 0) { @@ -811,14 +788,16 @@ */ if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) { if (oidp->oid_refcnt == 1) { - SLIST_FOREACH_SAFE(p, - SYSCTL_CHILDREN(oidp), oid_link, tmp) { + for(p = SPLAY_MIN(sysctl_oid_list, &oidp->oid_children); + p != NULL; p = tmp) { if (!recurse) { printf("Warning: failed attempt to " "remove oid %s with child %s\n", oidp->oid_name, p->oid_name); return (ENOTEMPTY); } + tmp = SPLAY_NEXT(sysctl_oid_list, + &oidp->oid_children, p); error = sysctl_remove_oid_locked(p, del, recurse); if (error) @@ -876,7 +855,7 @@ return(NULL); escaped = sysctl_escape_name(name); /* Check if the node already exists, otherwise create it */ - SYSCTL_WLOCK(); + SYSCTL_LOCK(); oidp = sysctl_find_oidname(escaped, parent); if (oidp != NULL) { free(escaped, M_SYSCTLOID); @@ -885,17 +864,17 @@ /* Update the context */ if (clist != NULL) sysctl_ctx_entry_add(clist, oidp); - SYSCTL_WUNLOCK(); + SYSCTL_UNLOCK(); return (oidp); } else { sysctl_warn_reuse(__func__, oidp); - SYSCTL_WUNLOCK(); + SYSCTL_UNLOCK(); return (NULL); } } oidp = malloc(sizeof(struct sysctl_oid), M_SYSCTLOID, M_WAITOK|M_ZERO); oidp->oid_parent = parent; - SLIST_INIT(&oidp->oid_children); + SPLAY_INIT(&oidp->oid_children); oidp->oid_number = number; oidp->oid_refcnt = 1; oidp->oid_name = escaped; @@ -913,7 +892,7 @@ sysctl_ctx_entry_add(clist, oidp); /* Register this oid */ sysctl_register_oid(oidp); - SYSCTL_WUNLOCK(); + SYSCTL_UNLOCK(); return (oidp); } @@ -927,10 +906,10 @@ char *oldname; newname = strdup(name, M_SYSCTLOID); - SYSCTL_WLOCK(); + SYSCTL_LOCK(); oldname = __DECONST(char *, oidp->oid_name); oidp->oid_name = newname; - SYSCTL_WUNLOCK(); + SYSCTL_UNLOCK(); free(oldname, M_SYSCTLOID); } @@ -942,21 +921,21 @@ { struct sysctl_oid *oidp; - SYSCTL_WLOCK(); + SYSCTL_LOCK(); if (oid->oid_parent == parent) { - SYSCTL_WUNLOCK(); + SYSCTL_UNLOCK(); return (0); } oidp = sysctl_find_oidname(oid->oid_name, parent); if (oidp != NULL) { - SYSCTL_WUNLOCK(); + SYSCTL_UNLOCK(); return (EEXIST); } sysctl_unregister_oid(oid); oid->oid_parent = parent; oid->oid_number = OID_AUTO; sysctl_register_oid(oid); - SYSCTL_WUNLOCK(); + SYSCTL_UNLOCK(); return (0); } @@ -973,10 +952,10 @@ sx_init(&sysctlmemlock, "sysctl mem"); sx_init(&sysctlstringlock, "sysctl string handler"); SYSCTL_INIT(); - SYSCTL_WLOCK(); + SYSCTL_LOCK(); SET_FOREACH(oidp, sysctl_set) sysctl_register_oid(*oidp); - SYSCTL_WUNLOCK(); + SYSCTL_UNLOCK(); } SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_FIRST, sysctl_register_all, NULL); @@ -1016,7 +995,7 @@ struct sysctl_oid *oidp; SYSCTL_ASSERT_LOCKED(); - SLIST_FOREACH(oidp, l, oid_link) { + SPLAY_FOREACH(oidp, sysctl_oid_list, l) { for (k=0; ktd, PRIV_SYSCTL_DEBUG); if (error) return (error); - SYSCTL_RLOCK(&tracker); + SYSCTL_LOCK(); sysctl_sysctl_debug_dump_node(&sysctl__children, 0); - SYSCTL_RUNLOCK(&tracker); + SYSCTL_UNLOCK(); return (ENOENT); } @@ -1081,16 +1059,15 @@ int *name = (int *) arg1; u_int namelen = arg2; int error; - struct sysctl_oid *oid; + struct sysctl_oid *oid, key; struct sysctl_oid_list *lsp = &sysctl__children, *lsp2; - struct rm_priotracker tracker; char buf[10]; error = sysctl_wire_old_buffer(req, 0); if (error) return (error); - SYSCTL_RLOCK(&tracker); + SYSCTL_LOCK(); while (namelen) { if (!lsp) { snprintf(buf,sizeof(buf),"%d",*name); @@ -1105,10 +1082,9 @@ continue; } lsp2 = NULL; - SLIST_FOREACH(oid, lsp, oid_link) { - if (oid->oid_number != *name) - continue; - + key.oid_number = *name; + oid = SPLAY_FIND(sysctl_oid_list, lsp, &key); + if (oid) { if (req->oldidx) error = SYSCTL_OUT(req, ".", 1); if (!error) @@ -1120,20 +1096,15 @@ namelen--; name++; - if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE) - break; - - if (oid->oid_handler) - break; - - lsp2 = SYSCTL_CHILDREN(oid); - break; + if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE && + !oid->oid_handler) + lsp2 = SYSCTL_CHILDREN(oid); } lsp = lsp2; } error = SYSCTL_OUT(req, "", 1); out: - SYSCTL_RUNLOCK(&tracker); + SYSCTL_UNLOCK(); return (error); } @@ -1239,13 +1210,25 @@ sysctl_sysctl_next_action(struct sysctl_oid_list *lsp, int *name, u_int namelen, int *next, int *len, int level, bool honor_skip) { - struct sysctl_oid *oidp; + struct sysctl_oid_list *next_lsp; + struct sysctl_oid *oidp = NULL, key; bool success = false; enum sysctl_iter_action action; SYSCTL_ASSERT_LOCKED(); - SLIST_FOREACH(oidp, lsp, oid_link) { - action = sysctl_sysctl_next_node(oidp, name, namelen, honor_skip); + /* + * Start the search at the requested oid. But if not found, then scan + * through all children. + */ + if (namelen > 0) { + key.oid_number = *name; + oidp = SPLAY_FIND(sysctl_oid_list, lsp, &key); + } + if (!oidp) + oidp = SPLAY_MIN(sysctl_oid_list, lsp); + for(; oidp != NULL; oidp = SPLAY_NEXT(sysctl_oid_list, lsp, oidp)) { + action = sysctl_sysctl_next_node(oidp, name, namelen, + honor_skip); if (action == ITER_SIBLINGS) continue; if (action == ITER_FOUND) { @@ -1254,13 +1237,13 @@ } KASSERT((action== ITER_CHILDREN), ("ret(%d)!=ITER_CHILDREN", action)); - lsp = SYSCTL_CHILDREN(oidp); + next_lsp = SYSCTL_CHILDREN(oidp); if (namelen == 0) { - success = sysctl_sysctl_next_action(lsp, NULL, 0, + success = sysctl_sysctl_next_action(next_lsp, NULL, 0, next + 1, len, level + 1, honor_skip); } else { - success = sysctl_sysctl_next_action(lsp, name + 1, namelen - 1, - next + 1, len, level + 1, honor_skip); + success = sysctl_sysctl_next_action(next_lsp, name + 1, + namelen - 1, next + 1, len, level + 1, honor_skip); if (!success) { /* @@ -1296,14 +1279,13 @@ int len, error; bool success; struct sysctl_oid_list *lsp = &sysctl__children; - struct rm_priotracker tracker; int next[CTL_MAXNAME]; len = 0; - SYSCTL_RLOCK(&tracker); + SYSCTL_LOCK(); success = sysctl_sysctl_next_action(lsp, name, namelen, next, &len, 1, oidp->oid_number == CTL_SYSCTL_NEXT); - SYSCTL_RUNLOCK(&tracker); + SYSCTL_UNLOCK(); if (!success) return (ENOENT); error = SYSCTL_OUT(req, next, len * sizeof (int)); @@ -1332,13 +1314,12 @@ for (*len = 0; *len < CTL_MAXNAME;) { p = strsep(&name, "."); - oidp = SLIST_FIRST(lsp); - for (;; oidp = SLIST_NEXT(oidp, oid_link)) { - if (oidp == NULL) - return (ENOENT); + SPLAY_FOREACH(oidp, sysctl_oid_list, lsp) { if (strcmp(p, oidp->oid_name) == 0) break; } + if (oidp == NULL) + return (ENOENT); *oid++ = oidp->oid_number; (*len)++; @@ -1365,7 +1346,6 @@ char *p; int error, oid[CTL_MAXNAME], len = 0; struct sysctl_oid *op = NULL; - struct rm_priotracker tracker; char buf[32]; if (!req->newlen) @@ -1386,9 +1366,9 @@ p [req->newlen] = '\0'; - SYSCTL_RLOCK(&tracker); + SYSCTL_LOCK(); error = name2oid(p, oid, &len, &op); - SYSCTL_RUNLOCK(&tracker); + SYSCTL_UNLOCK(); if (p != buf) free(p, M_SYSCTL); @@ -1412,14 +1392,13 @@ sysctl_sysctl_oidfmt(SYSCTL_HANDLER_ARGS) { struct sysctl_oid *oid; - struct rm_priotracker tracker; int error; error = sysctl_wire_old_buffer(req, 0); if (error) return (error); - SYSCTL_RLOCK(&tracker); + SYSCTL_LOCK(); error = sysctl_find_oid(arg1, arg2, &oid, NULL, req); if (error) goto out; @@ -1433,7 +1412,7 @@ goto out; error = SYSCTL_OUT(req, oid->oid_fmt, strlen(oid->oid_fmt) + 1); out: - SYSCTL_RUNLOCK(&tracker); + SYSCTL_UNLOCK(); return (error); } @@ -1444,14 +1423,13 @@ sysctl_sysctl_oiddescr(SYSCTL_HANDLER_ARGS) { struct sysctl_oid *oid; - struct rm_priotracker tracker; int error; error = sysctl_wire_old_buffer(req, 0); if (error) return (error); - SYSCTL_RLOCK(&tracker); + SYSCTL_LOCK(); error = sysctl_find_oid(arg1, arg2, &oid, NULL, req); if (error) goto out; @@ -1462,7 +1440,7 @@ } error = SYSCTL_OUT(req, oid->oid_descr, strlen(oid->oid_descr) + 1); out: - SYSCTL_RUNLOCK(&tracker); + SYSCTL_UNLOCK(); return (error); } @@ -1473,14 +1451,13 @@ sysctl_sysctl_oidlabel(SYSCTL_HANDLER_ARGS) { struct sysctl_oid *oid; - struct rm_priotracker tracker; int error; error = sysctl_wire_old_buffer(req, 0); if (error) return (error); - SYSCTL_RLOCK(&tracker); + SYSCTL_LOCK(); error = sysctl_find_oid(arg1, arg2, &oid, NULL, req); if (error) goto out; @@ -1491,7 +1468,7 @@ } error = SYSCTL_OUT(req, oid->oid_label, strlen(oid->oid_label) + 1); out: - SYSCTL_RUNLOCK(&tracker); + SYSCTL_UNLOCK(); return (error); } @@ -2162,16 +2139,15 @@ { struct sysctl_oid_list *lsp; struct sysctl_oid *oid; + struct sysctl_oid key; int indx; SYSCTL_ASSERT_LOCKED(); lsp = &sysctl__children; indx = 0; while (indx < CTL_MAXNAME) { - SLIST_FOREACH(oid, lsp, oid_link) { - if (oid->oid_number == name[indx]) - break; - } + key.oid_number = name[indx]; + oid = SPLAY_FIND(sysctl_oid_list, lsp, &key); if (oid == NULL) return (ENOENT); @@ -2211,10 +2187,9 @@ sysctl_root(SYSCTL_HANDLER_ARGS) { struct sysctl_oid *oid; - struct rm_priotracker tracker; int error, indx, lvl; - SYSCTL_RLOCK(&tracker); + SYSCTL_LOCK(); error = sysctl_find_oid(arg1, arg2, &oid, &indx, req); if (error) @@ -2302,10 +2277,10 @@ if ((oid->oid_kind & CTLFLAG_VNET) && arg1 != NULL) arg1 = (void *)(curvnet->vnet_data_base + (uintptr_t)arg1); #endif - error = sysctl_root_handler_locked(oid, arg1, arg2, req, &tracker); + error = sysctl_root_handler_locked(oid, arg1, arg2, req); out: - SYSCTL_RUNLOCK(&tracker); + SYSCTL_UNLOCK(); return (error); } diff --git a/sys/kern/vfs_init.c b/sys/kern/vfs_init.c --- a/sys/kern/vfs_init.c +++ b/sys/kern/vfs_init.c @@ -525,7 +525,7 @@ * number. */ sysctl_wlock(); - SLIST_FOREACH(oidp, SYSCTL_CHILDREN(&sysctl___vfs), oid_link) { + SPLAY_FOREACH(oidp, sysctl_oid_list, SYSCTL_CHILDREN(&sysctl___vfs)) { if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) { sysctl_unregister_oid(oidp); oidp->oid_number = vfc->vfc_typenum; diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h --- a/sys/sys/sysctl.h +++ b/sys/sys/sysctl.h @@ -39,7 +39,8 @@ #define _SYS_SYSCTL_H_ #ifdef _KERNEL -#include +#include +#include #endif /* @@ -173,20 +174,25 @@ int flags; }; -SLIST_HEAD(sysctl_oid_list, sysctl_oid); +struct sysctl_oid; + +/* Splay handling */ +SPLAY_HEAD(sysctl_oid_list, sysctl_oid); /* * This describes one "oid" in the MIB tree. Potentially more nodes can * be hidden behind it, expanded by the handler. */ struct sysctl_oid { - struct sysctl_oid_list oid_children; - struct sysctl_oid_list *oid_parent; - SLIST_ENTRY(sysctl_oid) oid_link; + struct sysctl_oid_list oid_children; + struct sysctl_oid_list* oid_parent; + SPLAY_ENTRY(sysctl_oid) oid_link; + /* Sort key for all siblings, and lookup key for userland */ int oid_number; u_int oid_kind; void *oid_arg1; intmax_t oid_arg2; + /* Must be unique amongst all siblings. */ const char *oid_name; int (*oid_handler)(SYSCTL_HANDLER_ARGS); const char *oid_fmt; @@ -196,6 +202,19 @@ const char *oid_label; }; +static inline int +cmp_splay_oid(struct sysctl_oid *a, struct sysctl_oid *b) +{ + if (a->oid_number > b->oid_number) + return (1); + else if (a->oid_number < b->oid_number) + return (-1); + else + return (0); +} + +SPLAY_PROTOTYPE(sysctl_oid_list, sysctl_oid, oid_link, cmp_splay_oid); + #define SYSCTL_IN(r, p, l) (r->newfunc)(r, p, l) #define SYSCTL_OUT(r, p, l) (r->oldfunc)(r, p, l) #define SYSCTL_OUT_STR(r, p) (r->oldfunc)(r, p, strlen(p) + 1) @@ -275,7 +294,7 @@ #define SYSCTL_OID_RAW(id, parent_child_head, nbr, name, kind, a1, a2, handler, fmt, descr, label) \ struct sysctl_oid id = { \ .oid_parent = (parent_child_head), \ - .oid_children = SLIST_HEAD_INITIALIZER(&id.oid_children), \ + .oid_children = SPLAY_INITIALIZER(&id.oid_children), \ .oid_number = (nbr), \ .oid_kind = (kind), \ .oid_arg1 = (a1), \