From nobody Wed Sep 28 16:33:38 2022 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4Md2B86YMGz4ckR0; Wed, 28 Sep 2022 16:33:52 +0000 (UTC) (envelope-from asomers@gmail.com) Received: from mail-ua1-f49.google.com (mail-ua1-f49.google.com [209.85.222.49]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (2048 bits) client-digest SHA256) (Client CN "smtp.gmail.com", Issuer "GTS CA 1D4" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Md2B86GWpz3pgZ; Wed, 28 Sep 2022 16:33:52 +0000 (UTC) (envelope-from asomers@gmail.com) Received: by mail-ua1-f49.google.com with SMTP id i17so4844468uaq.9; Wed, 28 Sep 2022 09:33:52 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc :subject:date; bh=zlG/dETVRDWEFSZOPnw36JNzN8qP9Wh0KmR+zp/2d7c=; b=arPuYRuE4fVKuqFOwUqT+qZSi+CCFvWG0ME0V3gzDvVSUDH6pWM3EVy3nW8cSFWWNs 0hN63aVk0ldVj2/xPKfLQx7dNmFsiRpjeCn6/3aIBjDW4CwCel5T7+ByJPNr4xnIabL+ L1JPqD0nb5JGGIYeSWhHy7FGpUWOz9AFgAJ7YKhtH15OANZFXW9hhEEDx5Jw2haREczT 06Soih3V+unedBA7YZeLPJ4RwiHvnecT3afx1oONDHa1HaPaj4CRY8OVCAjLScNdjwu+ ys/1kL8agzu9TGaMgbx9PRhufctXO6aGupkYkG9QAyJttLo+SWlX6O443Ta+AXXJq2HK UEWw== X-Gm-Message-State: ACrzQf06bnW2kOh2xkHp5LwMn4KMoUGA5r7fbOmTEEeDXiATEMImDEp8 f+NAVVh/UciGCYmTGqw/qSbGu6hpLsUgTFw0CznX0xpj X-Google-Smtp-Source: AMsMyM5pB3mAWm90t3z6q/EPLQKzTI6NbWifdA7LKu2fqg5i7dylXhxx70geNSSJsvUZIl+YKtWFf/WEdVgvR1hsym0= X-Received: by 2002:ab0:e05:0:b0:3bf:2088:64e1 with SMTP id g5-20020ab00e05000000b003bf208864e1mr15732700uak.118.1664382830987; Wed, 28 Sep 2022 09:33:50 -0700 (PDT) List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-main@freebsd.org X-BeenThere: dev-commits-src-main@freebsd.org MIME-Version: 1.0 References: <202209270004.28R04K1r086731@gitrepo.freebsd.org> In-Reply-To: From: Alan Somers Date: Wed, 28 Sep 2022 10:33:38 -0600 Message-ID: Subject: Re: git: d3f96f661050 - main - Fix O(n^2) behavior in sysctl To: Maxim Sobolev Cc: src-committers , dev-commits-src-all@freebsd.org, dev-commits-src-main@freebsd.org Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Spamd-Bar: ---- Authentication-Results: mx1.freebsd.org; none X-Rspamd-Queue-Id: 4Md2B86GWpz3pgZ X-Rspamd-Pre-Result: action=no action; module=replies; Message is reply to one we originated X-Spamd-Result: default: False [-4.00 / 15.00]; REPLY(-4.00)[] X-ThisMailContainsUnwantedMimeParts: N I don't think a different interface would necessarily fix all consistency problems, because there are probably additional consistency problems within ZFS itself. The ZFS stats just weren't designed to provide a consistent view, like "zpool status". But a different interface certainly could be much faster; sysctl is slow. Do you have any good ideas for how to easily create such an alternate interface? On Wed, Sep 28, 2022 at 10:19 AM Maxim Sobolev wrote: > > This also brings a question as to whether sysctl is the right interface t= o pull this data from the kernel in the first place? From my somewhat ignor= ant look this approach is likely to be poised with all sorts of race condit= ions, such so if configuration changes while you are pulling it out you'd g= et some inconsistent view that is not here not there. Wouldn't it be easier= to use some other mechanism to pull configuration of all 1,000 datasets as= one blob in one or few system calls? Like read(2) from /dev/zfsstats or so= mething like that? Then you can iterate over it as much as you need in user= land. > > -Max > > On Tue, Sep 27, 2022, 3:04 AM Alan Somers wrote: >> >> The branch main has been updated by asomers: >> >> URL: https://cgit.FreeBSD.org/src/commit/?id=3Dd3f96f661050e9bd21fe29931= 992a8b9e67ff189 >> >> commit d3f96f661050e9bd21fe29931992a8b9e67ff189 >> Author: Alan Somers >> AuthorDate: 2022-09-07 14:12:49 +0000 >> Commit: Alan Somers >> CommitDate: 2022-09-27 00:03:34 +0000 >> >> Fix O(n^2) behavior in sysctl >> >> Sysctl OIDs were internally stored in linked lists, triggering O(n^2= ) >> behavior when userland iterates over many of them. The slowdown is >> noticeable for MIBs that have > 100 children (for example, vm.uma). = But >> it's unignorable for kstat.zfs when a pool has > 1000 datasets. >> >> Convert the linked lists into RB trees. This produces a ~25x speedu= p >> for listing kstat.zfs with 4100 datasets, and no measurable penalty = for >> small dataset counts. >> >> Bump __FreeBSD_version for the KPI change. >> >> Sponsored by: Axcient >> Reviewed by: mjg >> Differential Revision: https://reviews.freebsd.org/D36500 >> --- >> sys/compat/linuxkpi/common/include/linux/sysfs.h | 2 +- >> sys/kern/kern_sysctl.c | 149 +++++++++++-----= ------- >> sys/kern/vfs_init.c | 2 +- >> sys/sys/param.h | 2 +- >> sys/sys/sysctl.h | 31 ++++- >> 5 files changed, 99 insertions(+), 87 deletions(-) >> >> diff --git a/sys/compat/linuxkpi/common/include/linux/sysfs.h b/sys/comp= at/linuxkpi/common/include/linux/sysfs.h >> index 0b6b479d9362..881a72e62ed9 100644 >> --- a/sys/compat/linuxkpi/common/include/linux/sysfs.h >> +++ b/sys/compat/linuxkpi/common/include/linux/sysfs.h >> @@ -246,7 +246,7 @@ sysfs_unmerge_group(struct kobject *kobj, const stru= ct attribute_group *grp) >> struct attribute **attr; >> struct sysctl_oid *oidp; >> >> - SLIST_FOREACH(oidp, SYSCTL_CHILDREN(kobj->oidp), oid_link) { >> + RB_FOREACH(oidp, sysctl_oid_list, SYSCTL_CHILDREN(kobj->oidp)) { >> if (strcmp(oidp->oid_name, grp->name) !=3D 0) >> continue; >> for (attr =3D grp->attrs; *attr !=3D NULL; attr++) { >> diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c >> index 9bc595f111cc..e1cd6ea4bd61 100644 >> --- a/sys/kern/kern_sysctl.c >> +++ b/sys/kern/kern_sysctl.c >> @@ -84,6 +84,8 @@ static MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl inter= nal magic"); >> static MALLOC_DEFINE(M_SYSCTLOID, "sysctloid", "sysctl dynamic oids"); >> static MALLOC_DEFINE(M_SYSCTLTMP, "sysctltmp", "sysctl temp output buff= er"); >> >> +RB_GENERATE(sysctl_oid_list, sysctl_oid, oid_link, cmp_sysctl_oid); >> + >> /* >> * The sysctllock protects the MIB tree. It also protects sysctl >> * contexts used with dynamic sysctls. The sysctl_register_oid() and >> @@ -120,7 +122,7 @@ static struct sx sysctlstringlock; >> static int sysctl_root(SYSCTL_HANDLER_ARGS); >> >> /* Root list */ >> -struct sysctl_oid_list sysctl__children =3D SLIST_HEAD_INITIALIZER(&sys= ctl__children); >> +struct sysctl_oid_list sysctl__children =3D RB_INITIALIZER(&sysctl__chi= ldren); >> >> static char* sysctl_escape_name(const char*); >> static int sysctl_remove_oid_locked(struct sysctl_oid *oidp, int de= l, >> @@ -134,7 +136,7 @@ sysctl_find_oidname(const char *name, struct sysctl_= oid_list *list) >> struct sysctl_oid *oidp; >> >> SYSCTL_ASSERT_LOCKED(); >> - SLIST_FOREACH(oidp, list, oid_link) { >> + RB_FOREACH(oidp, sysctl_oid_list, list) { >> if (strcmp(oidp->oid_name, name) =3D=3D 0) { >> return (oidp); >> } >> @@ -356,11 +358,14 @@ sysctl_search_oid(struct sysctl_oid **nodes, struc= t sysctl_oid *needle) >> indx =3D 0; >> while (indx < CTL_MAXNAME && indx >=3D 0) { >> if (nodes[indx] =3D=3D NULL && indx =3D=3D 0) >> - nodes[indx] =3D SLIST_FIRST(&sysctl__children); >> + nodes[indx] =3D RB_MIN(sysctl_oid_list, >> + &sysctl__children); >> else if (nodes[indx] =3D=3D NULL) >> - nodes[indx] =3D SLIST_FIRST(&nodes[indx - 1]->oi= d_children); >> + nodes[indx] =3D RB_MIN(sysctl_oid_list, >> + &nodes[indx - 1]->oid_children); >> else >> - nodes[indx] =3D SLIST_NEXT(nodes[indx], oid_link= ); >> + nodes[indx] =3D RB_NEXT(sysctl_oid_list, >> + &nodes[indx - 1]->oid_children, nodes[indx])= ; >> >> if (nodes[indx] =3D=3D needle) >> return (indx + 1); >> @@ -425,8 +430,7 @@ void >> sysctl_register_oid(struct sysctl_oid *oidp) >> { >> struct sysctl_oid_list *parent =3D oidp->oid_parent; >> - struct sysctl_oid *p; >> - struct sysctl_oid *q; >> + struct sysctl_oid *p, key; >> int oid_number; >> int timeout =3D 2; >> >> @@ -476,25 +480,21 @@ sysctl_register_oid(struct sysctl_oid *oidp) >> * Insert the OID into the parent's list sorted by OID number. >> */ >> retry: >> - q =3D NULL; >> - SLIST_FOREACH(p, parent, oid_link) { >> - /* check if the current OID number is in use */ >> - if (oid_number =3D=3D p->oid_number) { >> - /* get the next valid OID number */ >> - if (oid_number < CTL_AUTO_START || >> - oid_number =3D=3D 0x7fffffff) { >> - /* wraparound - restart */ >> - oid_number =3D CTL_AUTO_START; >> - /* don't loop forever */ >> - if (!timeout--) >> - panic("sysctl: Out of OID number= s\n"); >> - goto retry; >> - } else { >> - oid_number++; >> - } >> - } else if (oid_number < p->oid_number) >> - break; >> - q =3D p; >> + key.oid_number =3D oid_number; >> + p =3D RB_FIND(sysctl_oid_list, parent, &key); >> + if (p) { >> + /* get the next valid OID number */ >> + if (oid_number < CTL_AUTO_START || >> + oid_number =3D=3D 0x7fffffff) { >> + /* wraparound - restart */ >> + oid_number =3D 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 >=3D 0 && oidp->oid_number < CTL_AUTO_START= && >> @@ -504,10 +504,7 @@ retry: >> } >> /* update the OID number, if any */ >> oidp->oid_number =3D oid_number; >> - if (q !=3D NULL) >> - SLIST_INSERT_AFTER(q, oidp, oid_link); >> - else >> - SLIST_INSERT_HEAD(parent, oidp, oid_link); >> + RB_INSERT(sysctl_oid_list, parent, oidp); >> >> if ((oidp->oid_kind & CTLTYPE) !=3D CTLTYPE_NODE && >> #ifdef VIMAGE >> @@ -556,7 +553,6 @@ sysctl_enable_oid(struct sysctl_oid *oidp) >> void >> sysctl_unregister_oid(struct sysctl_oid *oidp) >> { >> - struct sysctl_oid *p; >> int error; >> >> SYSCTL_ASSERT_WLOCKED(); >> @@ -564,14 +560,8 @@ sysctl_unregister_oid(struct sysctl_oid *oidp) >> error =3D EINVAL; >> } else { >> error =3D ENOENT; >> - SLIST_FOREACH(p, oidp->oid_parent, oid_link) { >> - if (p =3D=3D oidp) { >> - SLIST_REMOVE(oidp->oid_parent, oidp, >> - sysctl_oid, oid_link); >> - error =3D 0; >> - break; >> - } >> - } >> + if (RB_REMOVE(sysctl_oid_list, oidp->oid_parent, oidp)) >> + error =3D 0; >> } >> >> /* >> @@ -732,17 +722,14 @@ int >> 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 =3D ENOENT; >> SYSCTL_WLOCK(); >> - SLIST_FOREACH_SAFE(p, SYSCTL_CHILDREN(parent), oid_link, tmp) { >> - if (strcmp(p->oid_name, name) =3D=3D 0) { >> - error =3D sysctl_remove_oid_locked(p, del, recur= se); >> - break; >> - } >> - } >> + p =3D sysctl_find_oidname(name, &parent->oid_children); >> + if (p) >> + error =3D sysctl_remove_oid_locked(p, del, recurse); >> SYSCTL_WUNLOCK(); >> >> return (error); >> @@ -811,14 +798,16 @@ sysctl_remove_oid_locked(struct sysctl_oid *oidp, = int del, int recurse) >> */ >> if ((oidp->oid_kind & CTLTYPE) =3D=3D CTLTYPE_NODE) { >> if (oidp->oid_refcnt =3D=3D 1) { >> - SLIST_FOREACH_SAFE(p, >> - SYSCTL_CHILDREN(oidp), oid_link, tmp) { >> + for(p =3D RB_MIN(sysctl_oid_list, &oidp->oid_chi= ldren); >> + p !=3D NULL; p =3D tmp) { >> if (!recurse) { >> printf("Warning: failed attempt = to " >> "remove oid %s with child %s= \n", >> oidp->oid_name, p->oid_name)= ; >> return (ENOTEMPTY); >> } >> + tmp =3D RB_NEXT(sysctl_oid_list, >> + &oidp->oid_children, p); >> error =3D sysctl_remove_oid_locked(p, de= l, >> recurse); >> if (error) >> @@ -895,7 +884,7 @@ sysctl_add_oid(struct sysctl_ctx_list *clist, struct= sysctl_oid_list *parent, >> } >> oidp =3D malloc(sizeof(struct sysctl_oid), M_SYSCTLOID, M_WAITOK= |M_ZERO); >> oidp->oid_parent =3D parent; >> - SLIST_INIT(&oidp->oid_children); >> + RB_INIT(&oidp->oid_children); >> oidp->oid_number =3D number; >> oidp->oid_refcnt =3D 1; >> oidp->oid_name =3D escaped; >> @@ -1016,7 +1005,7 @@ sysctl_sysctl_debug_dump_node(struct sysctl_oid_li= st *l, int i) >> struct sysctl_oid *oidp; >> >> SYSCTL_ASSERT_LOCKED(); >> - SLIST_FOREACH(oidp, l, oid_link) { >> + RB_FOREACH(oidp, sysctl_oid_list, l) { >> for (k=3D0; k> printf(" "); >> >> @@ -1081,7 +1070,7 @@ sysctl_sysctl_name(SYSCTL_HANDLER_ARGS) >> int *name =3D (int *) arg1; >> u_int namelen =3D arg2; >> int error; >> - struct sysctl_oid *oid; >> + struct sysctl_oid *oid, key; >> struct sysctl_oid_list *lsp =3D &sysctl__children, *lsp2; >> struct rm_priotracker tracker; >> char buf[10]; >> @@ -1105,10 +1094,9 @@ sysctl_sysctl_name(SYSCTL_HANDLER_ARGS) >> continue; >> } >> lsp2 =3D NULL; >> - SLIST_FOREACH(oid, lsp, oid_link) { >> - if (oid->oid_number !=3D *name) >> - continue; >> - >> + key.oid_number =3D *name; >> + oid =3D RB_FIND(sysctl_oid_list, lsp, &key); >> + if (oid) { >> if (req->oldidx) >> error =3D SYSCTL_OUT(req, ".", 1); >> if (!error) >> @@ -1120,14 +1108,9 @@ sysctl_sysctl_name(SYSCTL_HANDLER_ARGS) >> namelen--; >> name++; >> >> - if ((oid->oid_kind & CTLTYPE) !=3D CTLTYPE_NODE) >> - break; >> - >> - if (oid->oid_handler) >> - break; >> - >> - lsp2 =3D SYSCTL_CHILDREN(oid); >> - break; >> + if ((oid->oid_kind & CTLTYPE) =3D=3D CTLTYPE_NOD= E && >> + !oid->oid_handler) >> + lsp2 =3D SYSCTL_CHILDREN(oid); >> } >> lsp =3D lsp2; >> } >> @@ -1239,13 +1222,25 @@ static bool >> 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 =3D NULL, key; >> bool success =3D false; >> enum sysctl_iter_action action; >> >> SYSCTL_ASSERT_LOCKED(); >> - SLIST_FOREACH(oidp, lsp, oid_link) { >> - action =3D sysctl_sysctl_next_node(oidp, name, namelen, = honor_skip); >> + /* >> + * Start the search at the requested oid. But if not found, the= n scan >> + * through all children. >> + */ >> + if (namelen > 0) { >> + key.oid_number =3D *name; >> + oidp =3D RB_FIND(sysctl_oid_list, lsp, &key); >> + } >> + if (!oidp) >> + oidp =3D RB_MIN(sysctl_oid_list, lsp); >> + for(; oidp !=3D NULL; oidp =3D RB_NEXT(sysctl_oid_list, lsp, oid= p)) { >> + action =3D sysctl_sysctl_next_node(oidp, name, namelen, >> + honor_skip); >> if (action =3D=3D ITER_SIBLINGS) >> continue; >> if (action =3D=3D ITER_FOUND) { >> @@ -1254,13 +1249,13 @@ sysctl_sysctl_next_action(struct sysctl_oid_list= *lsp, int *name, u_int namelen, >> } >> KASSERT((action=3D=3D ITER_CHILDREN), ("ret(%d)!=3DITER_= CHILDREN", action)); >> >> - lsp =3D SYSCTL_CHILDREN(oidp); >> + next_lsp =3D SYSCTL_CHILDREN(oidp); >> if (namelen =3D=3D 0) { >> - success =3D sysctl_sysctl_next_action(lsp, NULL,= 0, >> + success =3D sysctl_sysctl_next_action(next_lsp, = NULL, 0, >> next + 1, len, level + 1, honor_skip); >> } else { >> - success =3D sysctl_sysctl_next_action(lsp, name = + 1, namelen - 1, >> - next + 1, len, level + 1, honor_skip); >> + success =3D sysctl_sysctl_next_action(next_lsp, = name + 1, >> + namelen - 1, next + 1, len, level + 1, honor= _skip); >> if (!success) { >> >> /* >> @@ -1332,13 +1327,12 @@ name2oid(char *name, int *oid, int *len, struct = sysctl_oid **oidpp) >> for (*len =3D 0; *len < CTL_MAXNAME;) { >> p =3D strsep(&name, "."); >> >> - oidp =3D SLIST_FIRST(lsp); >> - for (;; oidp =3D SLIST_NEXT(oidp, oid_link)) { >> - if (oidp =3D=3D NULL) >> - return (ENOENT); >> + RB_FOREACH(oidp, sysctl_oid_list, lsp) { >> if (strcmp(p, oidp->oid_name) =3D=3D 0) >> break; >> } >> + if (oidp =3D=3D NULL) >> + return (ENOENT); >> *oid++ =3D oidp->oid_number; >> (*len)++; >> >> @@ -2162,16 +2156,15 @@ sysctl_find_oid(int *name, u_int namelen, struct= sysctl_oid **noid, >> { >> struct sysctl_oid_list *lsp; >> struct sysctl_oid *oid; >> + struct sysctl_oid key; >> int indx; >> >> SYSCTL_ASSERT_LOCKED(); >> lsp =3D &sysctl__children; >> indx =3D 0; >> while (indx < CTL_MAXNAME) { >> - SLIST_FOREACH(oid, lsp, oid_link) { >> - if (oid->oid_number =3D=3D name[indx]) >> - break; >> - } >> + key.oid_number =3D name[indx]; >> + oid =3D RB_FIND(sysctl_oid_list, lsp, &key); >> if (oid =3D=3D NULL) >> return (ENOENT); >> >> diff --git a/sys/kern/vfs_init.c b/sys/kern/vfs_init.c >> index 6572a8e362c2..6e2e78aaf597 100644 >> --- a/sys/kern/vfs_init.c >> +++ b/sys/kern/vfs_init.c >> @@ -525,7 +525,7 @@ vfs_register(struct vfsconf *vfc) >> * number. >> */ >> sysctl_wlock(); >> - SLIST_FOREACH(oidp, SYSCTL_CHILDREN(&sysctl___vfs), oid_link) { >> + RB_FOREACH(oidp, sysctl_oid_list, SYSCTL_CHILDREN(&sysctl___vfs)= ) { >> if (strcmp(oidp->oid_name, vfc->vfc_name) =3D=3D 0) { >> sysctl_unregister_oid(oidp); >> oidp->oid_number =3D vfc->vfc_typenum; >> diff --git a/sys/sys/param.h b/sys/sys/param.h >> index f875d839d41f..3f5da06ef951 100644 >> --- a/sys/sys/param.h >> +++ b/sys/sys/param.h >> @@ -76,7 +76,7 @@ >> * cannot include sys/param.h and should only be updated here. >> */ >> #undef __FreeBSD_version >> -#define __FreeBSD_version 1400070 >> +#define __FreeBSD_version 1400071 >> >> /* >> * __FreeBSD_kernel__ indicates that this system uses the kernel of Fre= eBSD, >> diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h >> index 451d83bbe125..3bd77cf87243 100644 >> --- 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 @@ struct sysctl_req { >> int flags; >> }; >> >> -SLIST_HEAD(sysctl_oid_list, sysctl_oid); >> +struct sysctl_oid; >> + >> +/* RB Tree handling */ >> +RB_HEAD(sysctl_oid_list, sysctl_oid); >> >> /* >> * This describes one "oid" in the MIB tree. Potentially more nodes ca= n >> * 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; >> + RB_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 @@ struct sysctl_oid { >> const char *oid_label; >> }; >> >> +static inline int >> +cmp_sysctl_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); >> +} >> + >> +RB_PROTOTYPE(sysctl_oid_list, sysctl_oid, oid_link, cmp_sysctl_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 @@ TAILQ_HEAD(sysctl_ctx_list, sysctl_ctx_entry); >> #define SYSCTL_OID_RAW(id, parent_child_head, nbr, name, kind, a= 1, a2, handler, fmt, descr, label) \ >> struct sysctl_oid id =3D { = \ >> .oid_parent =3D (parent_child_head), = \ >> - .oid_children =3D SLIST_HEAD_INITIALIZER(&id.oid_childre= n), \ >> + .oid_children =3D RB_INITIALIZER(&id.oid_children), \ >> .oid_number =3D (nbr), = \ >> .oid_kind =3D (kind), = \ >> .oid_arg1 =3D (a1), = \ >>