pcb table auto resize (Re: diff: add tuning variables to config(8))

2014-06-27 Thread YASUOKA Masahiko
Hi,

On Tue, 17 Jun 2014 12:48:24 +0900 (JST)
YASUOKA Masahiko  wrote:
> On Mon, 16 Jun 2014 11:35:07 -0600
> Theo de Raadt  wrote:
>>> > Followings are our kernel variables' default:
>>> > 
>>> >   - sb_max: 256K
>>> >   - tcbhash_size: 128
>>> >   - udbhash_size: 128
>>> > 
>>> > These variables are sometime too small for busy server or gateway.
>>> > 
>>> > I'd like to modify config(8) to customize these variables without
>>> > recompiling the kernel. 
>>> 
>>> If we go this route, I would rather have a generic command (such as "set
>>>  ") to change kernel variables.
>>> 
>>> The list of said variables would still be restricted to what a given
>>> config(8) knows, to prevent people from tinkering with things they are
>>> not supposed to touch.
>> 
>> I quite dislike the direction this is going.
>> 
>> It seems like you have found 3 variables which should auto-tune.
>> So why not write kernel code to auto-tune them?
> 
> I didn't notice that way, but auto-tune seems better.
> 
> I modified in_pcbtable to resize automatically if the number of pcb
> entries beyonds 75% of the hash size.  I'm testing this.

I've tested and any problem was not found.

As far as my test, this improved relayd's HTTP connection relay rate
from 5000 conn/sec to 8000 conn/sec on Core2 Duo.

ok?

Resize the pcb hashtable automatically.  The table size will be doubled
when the number of the hash entries reaches 75% of the table size.

Index: sys/netinet/in_pcb.c
===
RCS file: /disk/cvs/openbsd/src/sys/netinet/in_pcb.c,v
retrieving revision 1.156
diff -u -p -r1.156 in_pcb.c
--- sys/netinet/in_pcb.c4 Jun 2014 13:45:47 -   1.156
+++ sys/netinet/in_pcb.c27 Jun 2014 09:53:27 -
@@ -118,6 +118,10 @@ struct baddynamicports baddynamicports;
 struct pool inpcb_pool;
 int inpcb_pool_initialized = 0;
 
+int in_pcbresize (struct inpcbtable *, int);
+
+#defineINPCBHASH_LOADFACTOR(_x)(((_x) * 3) / 4)
+
 #defineINPCBHASH(table, faddr, fport, laddr, lport, rdom) \
&(table)->inpt_hashtbl[(ntohl((faddr)->s_addr) + \
ntohs((fport)) + ntohs((lport)) + (rdom)) & (table->inpt_hash)]
@@ -144,6 +148,7 @@ in_pcbinit(struct inpcbtable *table, int
if (table->inpt_lhashtbl == NULL)
panic("in_pcbinit: hashinit failed for lport");
table->inpt_lastport = 0;
+   table->inpt_count = 0;
 }
 
 /*
@@ -191,6 +196,9 @@ in_pcballoc(struct socket *so, struct in
inp->inp_seclevel[SL_IPCOMP] = IPSEC_IPCOMP_LEVEL_DEFAULT;
inp->inp_rtableid = curproc->p_p->ps_rtableid;
s = splnet();
+   if (table->inpt_hash != 0 &&
+   table->inpt_count++ > INPCBHASH_LOADFACTOR(table->inpt_hash))
+   (void)in_pcbresize(table, (table->inpt_hash + 1) * 2);
TAILQ_INSERT_HEAD(&table->inpt_queue, inp, inp_queue);
LIST_INSERT_HEAD(INPCBLHASH(table, inp->inp_lport,
inp->inp_rtableid), inp, inp_lhash);
@@ -502,6 +510,7 @@ in_pcbdetach(struct inpcb *inp)
LIST_REMOVE(inp, inp_lhash);
LIST_REMOVE(inp, inp_hash);
TAILQ_REMOVE(&inp->inp_table->inpt_queue, inp, inp_queue);
+   inp->inp_table->inpt_count--;
splx(s);
pool_put(&inpcb_pool, inp);
 }
@@ -878,6 +887,39 @@ in_pcbrehash(struct inpcb *inp)
}
 #endif /* INET6 */
splx(s);
+}
+
+int
+in_pcbresize(struct inpcbtable *table, int hashsize)
+{
+   u_long nhash, nlhash;
+   void *nhashtbl, *nlhashtbl, *ohashtbl, *olhashtbl;
+   struct inpcb *inp0, *inp1;
+
+   ohashtbl = table->inpt_hashtbl;
+   olhashtbl = table->inpt_lhashtbl;
+
+   nhashtbl = hashinit(hashsize, M_PCB, M_NOWAIT, &nhash);
+   nlhashtbl = hashinit(hashsize, M_PCB, M_NOWAIT, &nlhash);
+   if (nhashtbl == NULL || nlhashtbl == NULL) {
+   if (nhashtbl != NULL)
+   free(nhashtbl, M_PCB);
+   if (nlhashtbl != NULL)
+   free(nlhashtbl, M_PCB);
+   return (ENOBUFS);
+   }
+   table->inpt_hashtbl = nhashtbl;
+   table->inpt_lhashtbl = nlhashtbl;
+   table->inpt_hash = nhash;
+   table->inpt_lhash = nlhash;
+
+   TAILQ_FOREACH_SAFE(inp0, &table->inpt_queue, inp_queue, inp1) {
+   in_pcbrehash(inp0);
+   }
+   free(ohashtbl, M_PCB);
+   free(olhashtbl, M_PCB);
+
+   return (0);
 }
 
 #ifdef DIAGNOSTIC
Index: sys/netinet/in_pcb.h
===
RCS file: /disk/cvs/openbsd/src/sys/netinet/in_pcb.h,v
retrieving revision 1.85
diff -u -p -r1.85 in_pcb.h
--- sys/netinet/in_pcb.h18 Apr 2014 10:48:29 -  1.85
+++ sys/netinet/in_pcb.h27 Jun 2014 09:52:26 -
@@ -158,6 +158,7 @@ struct inpcbtable {
LIST_HEAD(inpcbhead, inpcb) *inpt_hashtbl, *inpt_lhashtbl;
u_longinpt_hash, inpt_lhash;
u_int16_t inpt_lastport;
+   int   inpt_count;
 };
 
 /* f

Re: diff: add tuning variables to config(8)

2014-06-17 Thread YASUOKA Masahiko
Hi,

On Tue, 17 Jun 2014 09:43:07 +0200
Claudio Jeker  wrote:
> On Mon, Jun 16, 2014 at 11:35:07AM -0600, Theo de Raadt wrote:
>> > > Followings are our kernel variables' default:
>> > > 
>> > >   - sb_max: 256K
>> > >   - tcbhash_size: 128
>> > >   - udbhash_size: 128
>> > > 
>> > > These variables are sometime too small for busy server or gateway.
>> > > 
>> > > I'd like to modify config(8) to customize these variables without
>> > > recompiling the kernel. 
>> > 
>> > If we go this route, I would rather have a generic command (such as "set
>> >  ") to change kernel variables.
>> > 
>> > The list of said variables would still be restricted to what a given
>> > config(8) knows, to prevent people from tinkering with things they are
>> > not supposed to touch.
>> 
>> 
>> I quite dislike the direction this is going.
>> 
>> It seems like you have found 3 variables which should auto-tune.
>> So why not write kernel code to auto-tune them?
> 
> We could replace the hashes with RB trees. I think that would be better
> than having to rehash the list. To tune sb_max we need a way to have
> memory limits so that the socket buffers don't consume all the resources
> and starve the kernel out of memory. 

I think resizing the hash tables is better than replacing with RB
tree.

Hash
  pros:
- faster
- not so big
- easy to understand and customize(eg. adding lock for parallel)
  cons:
- need rehash when growing up

--yasuoka



Re: diff: add tuning variables to config(8)

2014-06-17 Thread Claudio Jeker
On Mon, Jun 16, 2014 at 11:35:07AM -0600, Theo de Raadt wrote:
> > > Followings are our kernel variables' default:
> > > 
> > >   - sb_max: 256K
> > >   - tcbhash_size: 128
> > >   - udbhash_size: 128
> > > 
> > > These variables are sometime too small for busy server or gateway.
> > > 
> > > I'd like to modify config(8) to customize these variables without
> > > recompiling the kernel. 
> > 
> > If we go this route, I would rather have a generic command (such as "set
> >  ") to change kernel variables.
> > 
> > The list of said variables would still be restricted to what a given
> > config(8) knows, to prevent people from tinkering with things they are
> > not supposed to touch.
> 
> 
> I quite dislike the direction this is going.
> 
> It seems like you have found 3 variables which should auto-tune.
> So why not write kernel code to auto-tune them?
> 

We could replace the hashes with RB trees. I think that would be better
than having to rehash the list. To tune sb_max we need a way to have
memory limits so that the socket buffers don't consume all the resources
and starve the kernel out of memory. 
I think implementing the RB tree is fairly trivial (I did this once 10
years ago) but resource management is a fair bit more work.

-- 
:wq Claudio



Re: diff: add tuning variables to config(8)

2014-06-16 Thread YASUOKA Masahiko
On Mon, 16 Jun 2014 11:35:07 -0600
Theo de Raadt  wrote:
>> > Followings are our kernel variables' default:
>> > 
>> >   - sb_max: 256K
>> >   - tcbhash_size: 128
>> >   - udbhash_size: 128
>> > 
>> > These variables are sometime too small for busy server or gateway.
>> > 
>> > I'd like to modify config(8) to customize these variables without
>> > recompiling the kernel. 
>> 
>> If we go this route, I would rather have a generic command (such as "set
>>  ") to change kernel variables.
>> 
>> The list of said variables would still be restricted to what a given
>> config(8) knows, to prevent people from tinkering with things they are
>> not supposed to touch.
> 
> I quite dislike the direction this is going.
> 
> It seems like you have found 3 variables which should auto-tune.
> So why not write kernel code to auto-tune them?

I didn't notice that way, but auto-tune seems better.

I modified in_pcbtable to resize automatically if the number of pcb
entries beyonds 75% of the hash size.  I'm testing this.

(currently I have no idea for sb_max.)

comments?

Index: sys/netinet/in_pcb.c
===
RCS file: /disk/cvs/openbsd/src/sys/netinet/in_pcb.c,v
retrieving revision 1.156
diff -u -p -r1.156 in_pcb.c
--- sys/netinet/in_pcb.c4 Jun 2014 13:45:47 -   1.156
+++ sys/netinet/in_pcb.c17 Jun 2014 03:36:35 -
@@ -118,6 +118,8 @@ struct baddynamicports baddynamicports;
 struct pool inpcb_pool;
 int inpcb_pool_initialized = 0;
 
+int in_pcbresize (struct inpcbtable *, int);
+
 #defineINPCBHASH(table, faddr, fport, laddr, lport, rdom) \
&(table)->inpt_hashtbl[(ntohl((faddr)->s_addr) + \
ntohs((fport)) + ntohs((lport)) + (rdom)) & (table->inpt_hash)]
@@ -144,6 +146,7 @@ in_pcbinit(struct inpcbtable *table, int
if (table->inpt_lhashtbl == NULL)
panic("in_pcbinit: hashinit failed for lport");
table->inpt_lastport = 0;
+   table->inpt_count = 0;
 }
 
 /*
@@ -191,6 +194,9 @@ in_pcballoc(struct socket *so, struct in
inp->inp_seclevel[SL_IPCOMP] = IPSEC_IPCOMP_LEVEL_DEFAULT;
inp->inp_rtableid = curproc->p_p->ps_rtableid;
s = splnet();
+   if (table->inpt_hash != 0 &&
+   table->inpt_count++ > (table->inpt_hash * 3) / 4)
+   (void)in_pcbresize(table, (table->inpt_hash + 1) * 2);
TAILQ_INSERT_HEAD(&table->inpt_queue, inp, inp_queue);
LIST_INSERT_HEAD(INPCBLHASH(table, inp->inp_lport,
inp->inp_rtableid), inp, inp_lhash);
@@ -502,6 +508,7 @@ in_pcbdetach(struct inpcb *inp)
LIST_REMOVE(inp, inp_lhash);
LIST_REMOVE(inp, inp_hash);
TAILQ_REMOVE(&inp->inp_table->inpt_queue, inp, inp_queue);
+   inp->inp_table->inpt_count--;
splx(s);
pool_put(&inpcb_pool, inp);
 }
@@ -878,6 +885,38 @@ in_pcbrehash(struct inpcb *inp)
}
 #endif /* INET6 */
splx(s);
+}
+
+int
+in_pcbresize(struct inpcbtable *table, int hashsize)
+{
+   u_long nhash, nlhash;
+   void *nhashtbl, *nlhashtbl, *ohashtbl, *olhashtbl;
+   struct inpcb *inp0, *inp1;
+
+   ohashtbl = table->inpt_hashtbl;
+   olhashtbl = table->inpt_lhashtbl;
+   nhashtbl = hashinit(hashsize, M_PCB, M_NOWAIT, &nhash);
+   nlhashtbl = hashinit(hashsize, M_PCB, M_NOWAIT, &nlhash);
+   if (nhashtbl == NULL || nlhashtbl == NULL) {
+   if (nhashtbl != NULL)
+   free(nhashtbl, M_PCB);
+   if (nlhashtbl != NULL)
+   free(nlhashtbl, M_PCB);
+   return (ENOBUFS);
+   }
+   table->inpt_hashtbl = nhashtbl;
+   table->inpt_lhashtbl = nlhashtbl;
+   table->inpt_hash = nhash;
+   table->inpt_lhash = nlhash;
+
+   TAILQ_FOREACH_SAFE(inp0, &table->inpt_queue, inp_queue, inp1) {
+   in_pcbrehash(inp0);
+   }
+   free(ohashtbl, M_PCB);
+   free(olhashtbl, M_PCB);
+
+   return (0);
 }
 
 #ifdef DIAGNOSTIC
Index: sys/netinet/in_pcb.h
===
RCS file: /disk/cvs/openbsd/src/sys/netinet/in_pcb.h,v
retrieving revision 1.85
diff -u -p -r1.85 in_pcb.h
--- sys/netinet/in_pcb.h18 Apr 2014 10:48:29 -  1.85
+++ sys/netinet/in_pcb.h17 Jun 2014 03:36:35 -
@@ -158,6 +158,7 @@ struct inpcbtable {
LIST_HEAD(inpcbhead, inpcb) *inpt_hashtbl, *inpt_lhashtbl;
u_longinpt_hash, inpt_lhash;
u_int16_t inpt_lastport;
+   int   inpt_count;
 };
 
 /* flags in inp_flags: */



Re: diff: add tuning variables to config(8)

2014-06-16 Thread Theo de Raadt
> > Followings are our kernel variables' default:
> > 
> >   - sb_max: 256K
> >   - tcbhash_size: 128
> >   - udbhash_size: 128
> > 
> > These variables are sometime too small for busy server or gateway.
> > 
> > I'd like to modify config(8) to customize these variables without
> > recompiling the kernel. 
> 
> If we go this route, I would rather have a generic command (such as "set
>  ") to change kernel variables.
> 
> The list of said variables would still be restricted to what a given
> config(8) knows, to prevent people from tinkering with things they are
> not supposed to touch.


I quite dislike the direction this is going.

It seems like you have found 3 variables which should auto-tune.
So why not write kernel code to auto-tune them?



Re: diff: add tuning variables to config(8)

2014-06-16 Thread Sebastian Reitenbach
 
On Monday, June 16, 2014 18:55 CEST, Miod Vallat  wrote: 
 
> > Followings are our kernel variables' default:
> > 
> >   - sb_max: 256K
> >   - tcbhash_size: 128
> >   - udbhash_size: 128
> > 
> > These variables are sometime too small for busy server or gateway.
> > 
> > I'd like to modify config(8) to customize these variables without
> > recompiling the kernel. 
> 
> If we go this route, I would rather have a generic command (such as "set
>  ") to change kernel variables.
> 
> The list of said variables would still be restricted to what a given
> config(8) knows, to prevent people from tinkering with things they are
> not supposed to touch.

at least for sb_max I once sent a patch  to tech@ [1] to change it via sysctl, 
but
that was unfortunately rejected ;)
So, I'd still find it easier to change the sysctl than a changing it with 
config(8).
But on the other hand, sysctl might be too easy to use for $average user,
and making it only accessible via config(8) may prevent whining users.

cheers,
Sebastian


[1 ] https://groups.google.com/forum/#!topic/mailing.openbsd.tech/kMRT8VO2VaA

> 
> Miod
> 
 
 
 
 




Re: diff: add tuning variables to config(8)

2014-06-16 Thread Miod Vallat
> Followings are our kernel variables' default:
> 
>   - sb_max: 256K
>   - tcbhash_size: 128
>   - udbhash_size: 128
> 
> These variables are sometime too small for busy server or gateway.
> 
> I'd like to modify config(8) to customize these variables without
> recompiling the kernel. 

If we go this route, I would rather have a generic command (such as "set
 ") to change kernel variables.

The list of said variables would still be restricted to what a given
config(8) knows, to prevent people from tinkering with things they are
not supposed to touch.

Miod



Re: diff: add tuning variables to config(8)

2014-06-16 Thread YASUOKA Masahiko
On Mon, 16 Jun 2014 21:28:55 +0900 (JST)
YASUOKA Masahiko  wrote:
> Followings are our kernel variables' default:
> 
>   - sb_max: 256K
>   - tcbhash_size: 128
>   - udbhash_size: 128
> 
> These variables are sometime too small for busy server or gateway.
> 
> I'd like to modify config(8) to customize these variables without
> recompiling the kernel. 
> 
> Comment or ok?

Let me update the diff.  Previous diff has some typos.

Index: usr.sbin/config/cmd.c
===
RCS file: /disk/cvs/openbsd/src/usr.sbin/config/cmd.c,v
retrieving revision 1.20
diff -u -p -r1.20 cmd.c
--- usr.sbin/config/cmd.c   23 Nov 2013 17:38:15 -  1.20
+++ usr.sbin/config/cmd.c   16 Jun 2014 12:25:59 -
@@ -24,7 +24,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include 
+#include 
 #include 
 #include 
 
@@ -61,6 +61,11 @@ cmd_table_t cmd_table[] = {
{"bufcachepercent", Xbufcachepct, "[number]",
 "Show/change BUFCACHEPERCENT"},
{"nkmempg", Xnkmempg,   "[number]", "Show/change NKMEMPAGES"},
+   {"sb_max", Xsb_max, "[number]", "Show/change sb_max"},
+   {"udbhashsize", Xudbhashsize, "[number]",
+"Show/change udbhashsize"},
+   {"tcbhashsize", Xtcbhashsize, "[number]",
+"Show/change tcbhashsize"},
{NULL, NULL,NULL,   NULL}
 };
 
@@ -313,5 +318,58 @@ int
 Xnkmempg(cmd_t *cmd)
 {
int_variable_adjust(cmd, I_NKMEMPG, "nkmempages");
+   return (CMD_CONT);
+}
+
+int
+Xsb_max(cmd_t *cmd)
+{
+   int_variable_adjust(cmd, I_SB_MAX, "sb_max");
+   return (CMD_CONT);
+}
+
+void
+pow2_variable_adjust(const cmd_t *cmd, int idx, const char *name)
+{
+   int i, *v, num;
+
+   if (nl[idx].n_type != 0) {
+   ukc_mod_kernel = 1;
+
+   v = (int *)adjust((caddr_t)(nl[idx].n_value));
+
+   if (strlen(cmd->args) == 0) {
+   printf("%s = %d\n", name, *v);
+   } else {
+   if (number(cmd->args, &num) == 0) {
+if (!powerof2(num)) {
+   for (i = 0; num; num = num >> 1)
+   i++;
+   num = 1 << i;
+   printf("Warning: number must be "
+   "power of 2.  Rounded up to %d\n",
+   num);
+   }
+   *v = num;
+   printf("%s = %d\n", name, num);
+   } else
+   printf("Unknown argument\n");
+   }
+   } else
+   printf("This kernel does not support modification of %s.\n",
+   name);
+}
+
+int
+Xudbhashsize(cmd_t *cmd)
+{
+   pow2_variable_adjust(cmd, I_UDBHASHSIZE, "udbhashsize");
+   return (CMD_CONT);
+}
+
+int
+Xtcbhashsize(cmd_t *cmd)
+{
+   pow2_variable_adjust(cmd, I_TCBHASHSIZE, "tcbhashsize");
return (CMD_CONT);
 }
Index: usr.sbin/config/cmd.h
===
RCS file: /disk/cvs/openbsd/src/usr.sbin/config/cmd.h,v
retrieving revision 1.7
diff -u -p -r1.7 cmd.h
--- usr.sbin/config/cmd.h   3 Jun 2003 00:52:35 -   1.7
+++ usr.sbin/config/cmd.h   16 Jun 2014 11:58:37 -
@@ -72,6 +72,9 @@ int Xbufcachepct(cmd_t *);
 int Xnkmempg(cmd_t *);
 int Xshmseg(cmd_t *);
 int Xshmmaxpgs(cmd_t *);
+int Xsb_max(cmd_t *);
+int Xudbhashsize(cmd_t *);
+int Xtcbhashsize(cmd_t *);
 
 #endif /* _CMD_H */
 
Index: usr.sbin/config/config.8
===
RCS file: /disk/cvs/openbsd/src/usr.sbin/config/config.8,v
retrieving revision 1.60
diff -u -p -r1.60 config.8
--- usr.sbin/config/config.820 Jan 2014 01:11:49 -  1.60
+++ usr.sbin/config/config.816 Jun 2014 12:41:49 -
@@ -321,6 +321,21 @@ is the number of minutes west of GMT and
 .Va dst
 is non-zero if Daylight Saving Time is in effect.
 Without arguments, displays its current value.
+.It Ic sb_max Op Ar number
+Change the sb_max value.
+Without arguments, displays its current value.
+.It Ic tcbhashsize Op Ar number
+Change the tcbhashsize value.
+Without arguments, displays its current value.
+The
+.Ar number
+should be power of 2, otherwise it will be rounded up forcibly.
+.It Ic udbhashsize Op Ar number
+Change the udbhashsize value.
+Without arguments, displays its current value.
+The
+.Ar number
+should be power of 2, otherwise it will be rounded up forcibly.
 .El
 .Sh EXAMPLES (kernel building)
 Note:
Index: usr.sbin/config/ukc.h
===
RCS file: /disk/cvs/openbsd/src/usr.sbin/config/ukc.h,v
retrieving revision 1.12
diff -u -p -r1.12 ukc.h
--- usr.sbin/config/ukc.h 

diff: add tuning variables to config(8)

2014-06-16 Thread YASUOKA Masahiko
Followings are our kernel variables' default:

  - sb_max: 256K
  - tcbhash_size: 128
  - udbhash_size: 128

These variables are sometime too small for busy server or gateway.

I'd like to modify config(8) to customize these variables without
recompiling the kernel. 

Comment or ok?

Index: usr.sbin/config/cmd.c
===
RCS file: /disk/cvs/openbsd/src/usr.sbin/config/cmd.c,v
retrieving revision 1.20
diff -u -p -r1.20 cmd.c
--- usr.sbin/config/cmd.c   23 Nov 2013 17:38:15 -  1.20
+++ usr.sbin/config/cmd.c   16 Jun 2014 12:25:59 -
@@ -24,7 +24,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include 
+#include 
 #include 
 #include 
 
@@ -61,6 +61,11 @@ cmd_table_t cmd_table[] = {
{"bufcachepercent", Xbufcachepct, "[number]",
 "Show/change BUFCACHEPERCENT"},
{"nkmempg", Xnkmempg,   "[number]", "Show/change NKMEMPAGES"},
+   {"sb_max", Xsb_max, "[number]", "Show/change sb_max"},
+   {"udbhashsize", Xudbhashsize, "[number]",
+"Show/change udbhashsize"},
+   {"tcbhashsize", Xtcbhashsize, "[number]",
+"Show/change tcbhashsize"},
{NULL, NULL,NULL,   NULL}
 };
 
@@ -313,5 +318,58 @@ int
 Xnkmempg(cmd_t *cmd)
 {
int_variable_adjust(cmd, I_NKMEMPG, "nkmempages");
+   return (CMD_CONT);
+}
+
+int
+Xsb_max(cmd_t *cmd)
+{
+   int_variable_adjust(cmd, I_SB_MAX, "sb_max");
+   return (CMD_CONT);
+}
+
+void
+pow2_variable_adjust(const cmd_t *cmd, int idx, const char *name)
+{
+   int i, *v, num;
+
+   if (nl[idx].n_type != 0) {
+   ukc_mod_kernel = 1;
+
+   v = (int *)adjust((caddr_t)(nl[idx].n_value));
+
+   if (strlen(cmd->args) == 0) {
+   printf("%s = %d\n", name, *v);
+   } else {
+   if (number(cmd->args, &num) == 0) {
+if (!powerof2(num)) {
+   for (i = 0; num; num = num >> 1)
+   i++;
+   num = 1 << i;
+   printf("Warning: number must be "
+   "power of 2.  Rounded up to %d\n",
+   num);
+   }
+   *v = num;
+   printf("%s = %d\n", name, num);
+   } else
+   printf("Unknown argument\n");
+   }
+   } else
+   printf("This kernel does not support modification of %s.\n",
+   name);
+}
+
+int
+Xudbhashsize(cmd_t *cmd)
+{
+   pow2_variable_adjust(cmd, I_UDBHASHSIZE, "udbhashsize");
+   return (CMD_CONT);
+}
+
+int
+Xtcbhashsize(cmd_t *cmd)
+{
+   pow2_variable_adjust(cmd, I_TCBHASHSIZE, "tcbhashsize");
return (CMD_CONT);
 }
Index: usr.sbin/config/cmd.h
===
RCS file: /disk/cvs/openbsd/src/usr.sbin/config/cmd.h,v
retrieving revision 1.7
diff -u -p -r1.7 cmd.h
--- usr.sbin/config/cmd.h   3 Jun 2003 00:52:35 -   1.7
+++ usr.sbin/config/cmd.h   16 Jun 2014 11:58:37 -
@@ -72,6 +72,9 @@ int Xbufcachepct(cmd_t *);
 int Xnkmempg(cmd_t *);
 int Xshmseg(cmd_t *);
 int Xshmmaxpgs(cmd_t *);
+int Xsb_max(cmd_t *);
+int Xudbhashsize(cmd_t *);
+int Xtcbhashsize(cmd_t *);
 
 #endif /* _CMD_H */
 
Index: usr.sbin/config/config.8
===
RCS file: /disk/cvs/openbsd/src/usr.sbin/config/config.8,v
retrieving revision 1.60
diff -u -p -r1.60 config.8
--- usr.sbin/config/config.820 Jan 2014 01:11:49 -  1.60
+++ usr.sbin/config/config.816 Jun 2014 11:58:37 -
@@ -321,6 +321,21 @@ is the number of minutes west of GMT and
 .Va dst
 is non-zero if Daylight Saving Time is in effect.
 Without arguments, displays its current value.
+.It Ic sb_max Op Ar number
+Change the sb_max value.
+Without arguments, displays its current value.
+.It Ic tcbhashsize Op Ar number
+Change the tcbhashsize value.
+Without arguments, displays its current value.
+The
+.Ar number
+should be power of 2, otherwise it will be rounded up forcibly.
+.It Ic udbhashsize Op Ar number
+Change the tcbhashsize value.
+Without arguments, displays its current value.
+The
+.Ar number
+should be power of 2, otherwise it will be rounded up forcibly.
 .El
 .Sh EXAMPLES (kernel building)
 Note:
Index: usr.sbin/config/ukc.h
===
RCS file: /disk/cvs/openbsd/src/usr.sbin/config/ukc.h,v
retrieving revision 1.12
diff -u -p -r1.12 ukc.h
--- usr.sbin/config/ukc.h   10 Dec 2009 22:07:19 -  1.12
+++ usr.sbin/config/ukc.h   16 Jun 2014 11:58:37 -
@@ -48,7 +48,10 @@
 #define I_NMBCLUSTERS  1