Hi,
I am running machines with a very large number of mbuf. netstat
-m output looks strange, I suspect integer overflow in kernel and
userland.
So I would like to convert kernel variables and calculations for
mbuf memory to long. The problem does not affect 32 bit machines,
they do not support so much memory. I put a range check into the
kernel sysctl. In netstat I cast all multiplications to unsigned
long, to hold the product of two unsigned int.
The sysctl kern.maxclusters can stay an int until we support 4 TB
of RAM.
ok?
bluhm
Index: sys/conf/param.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/conf/param.c,v
retrieving revision 1.41
diff -u -p -r1.41 param.c
--- sys/conf/param.c 8 Jul 2019 23:59:32 -0000 1.41
+++ sys/conf/param.c 12 Jul 2019 20:31:45 -0000
@@ -89,7 +89,7 @@ int initialvnodes = NVNODE;
int maxprocess = NPROCESS;
int maxthread = NPROCESS + 8 * MAXUSERS;
int maxfiles = 5 * (NPROCESS + MAXUSERS) + 80;
-int nmbclust = NMBCLUSTERS;
+long nmbclust = NMBCLUSTERS;
#ifndef MBLOWAT
#define MBLOWAT 16
Index: sys/kern/kern_sysctl.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/kern/kern_sysctl.c,v
retrieving revision 1.363
diff -u -p -r1.363 kern_sysctl.c
--- sys/kern/kern_sysctl.c 12 Jul 2019 13:56:27 -0000 1.363
+++ sys/kern/kern_sysctl.c 12 Jul 2019 21:50:48 -0000
@@ -129,8 +129,6 @@ extern int audio_record_enable;
int allowkmem;
-extern void nmbclust_update(void);
-
int sysctl_diskinit(int, struct proc *);
int sysctl_proc_args(int *, u_int, void *, size_t *, struct proc *);
int sysctl_proc_cwd(int *, u_int, void *, size_t *, struct proc *);
@@ -590,11 +588,13 @@ kern_sysctl(int *name, u_int namelen, vo
return (sysctl_wdog(name + 1, namelen - 1, oldp, oldlenp,
newp, newlen));
#endif
- case KERN_MAXCLUSTERS:
- error = sysctl_int(oldp, oldlenp, newp, newlen, &nmbclust);
- if (!error)
- nmbclust_update();
+ case KERN_MAXCLUSTERS: {
+ int val = nmbclust;
+ error = sysctl_int(oldp, oldlenp, newp, newlen, &val);
+ if (error == 0 && val != nmbclust)
+ error = nmbclust_update(val);
return (error);
+ }
#ifndef SMALL_KERNEL
case KERN_EVCOUNT:
return (evcount_sysctl(name + 1, namelen - 1, oldp, oldlenp,
Index: sys/kern/uipc_mbuf.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/kern/uipc_mbuf.c,v
retrieving revision 1.269
diff -u -p -r1.269 uipc_mbuf.c
--- sys/kern/uipc_mbuf.c 10 Jun 2019 23:45:19 -0000 1.269
+++ sys/kern/uipc_mbuf.c 12 Jul 2019 21:50:06 -0000
@@ -131,12 +131,11 @@ int max_hdr; /* largest link+protocol
struct mutex m_extref_mtx = MUTEX_INITIALIZER(IPL_NET);
void m_extfree(struct mbuf *);
-void nmbclust_update(void);
void m_zero(struct mbuf *);
struct mutex m_pool_mtx = MUTEX_INITIALIZER(IPL_NET);
-unsigned int mbuf_mem_limit; /* how much memory can be allocated */
-unsigned int mbuf_mem_alloc; /* how much memory has been allocated */
+unsigned long mbuf_mem_limit; /* how much memory can be allocated */
+unsigned long mbuf_mem_alloc; /* how much memory has been allocated */
void *m_pool_alloc(struct pool *, int, int *);
void m_pool_free(struct pool *, void *);
@@ -161,14 +160,15 @@ static u_int num_extfree_fns;
void
mbinit(void)
{
- int i;
+ int i, error;
unsigned int lowbits;
CTASSERT(MSIZE == sizeof(struct mbuf));
m_pool_allocator.pa_pagesz = pool_allocator_multi.pa_pagesz;
- nmbclust_update();
+ error = nmbclust_update(nmbclust);
+ KASSERT(error == 0);
mbuf_mem_alloc = 0;
#if DIAGNOSTIC
@@ -214,11 +214,15 @@ mbcpuinit()
pool_cache_init(&mclpools[i]);
}
-void
-nmbclust_update(void)
+int
+nmbclust_update(long newval)
{
+ if (newval > LONG_MAX / MCLBYTES)
+ return ERANGE;
/* update the global mbuf memory limit */
+ nmbclust = newval;
mbuf_mem_limit = nmbclust * MCLBYTES;
+ return 0;
}
/*
Index: sys/sys/mbuf.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/sys/mbuf.h,v
retrieving revision 1.244
diff -u -p -r1.244 mbuf.h
--- sys/sys/mbuf.h 10 Jun 2019 23:45:19 -0000 1.244
+++ sys/sys/mbuf.h 12 Jul 2019 21:10:06 -0000
@@ -402,7 +402,7 @@ struct mbuf_queue {
#ifdef _KERNEL
struct pool;
-extern int nmbclust; /* limit on the # of clusters */
+extern long nmbclust; /* limit on the # of clusters */
extern int mblowat; /* mbuf low water mark */
extern int mcllowat; /* mbuf cluster low water mark */
extern int max_linkhdr; /* largest link-level header */
@@ -411,6 +411,7 @@ extern int max_hdr; /* largest
link+pr
void mbinit(void);
void mbcpuinit(void);
+int nmbclust_update(long);
struct mbuf *m_copym(struct mbuf *, int, int, int);
struct mbuf *m_free(struct mbuf *);
struct mbuf *m_get(int, int);
Index: usr.bin/netstat/mbuf.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/usr.bin/netstat/mbuf.c,v
retrieving revision 1.42
diff -u -p -r1.42 mbuf.c
--- usr.bin/netstat/mbuf.c 28 Jun 2019 13:35:02 -0000 1.42
+++ usr.bin/netstat/mbuf.c 12 Jul 2019 21:20:10 -0000
@@ -184,17 +184,19 @@ mbpr(void)
mbstat.m_mtypes[i],
plural(mbstat.m_mtypes[i]), i);
}
- totmem = (mbpool.pr_npages * mbpool.pr_pgsize);
- totpeak = mbpool.pr_hiwat * mbpool.pr_pgsize;
+ totmem = (unsigned long)mbpool.pr_npages * mbpool.pr_pgsize;
+ totpeak = (unsigned long)mbpool.pr_hiwat * mbpool.pr_pgsize;
for (i = 0; i < mclp; i++) {
printf("%u/%lu mbuf %d byte clusters in use"
" (current/peak)\n",
mclpools[i].pr_nout,
(unsigned long)
- (mclpools[i].pr_hiwat * mclpools[i].pr_itemsperpage),
+ mclpools[i].pr_hiwat * mclpools[i].pr_itemsperpage,
mclpools[i].pr_size);
- totmem += (mclpools[i].pr_npages * mclpools[i].pr_pgsize);
- totpeak += mclpools[i].pr_hiwat * mclpools[i].pr_pgsize;
+ totmem += (unsigned long)
+ mclpools[i].pr_npages * mclpools[i].pr_pgsize;
+ totpeak += (unsigned long)
+ mclpools[i].pr_hiwat * mclpools[i].pr_pgsize;
}
printf("%lu/%lu/%lu Kbytes allocated to network "