summaryrefslogtreecommitdiff
path: root/usr.sbin/pstat
diff options
context:
space:
mode:
authorapb <apb@NetBSD.org>2012-11-10 11:01:52 +0000
committerapb <apb@NetBSD.org>2012-11-10 11:01:52 +0000
commitcbecdd0db3cc662ef69b27910a8d1d38a9ad55f6 (patch)
treefee58d2e5bd9c31fd88d93ec20719cc7b24df862 /usr.sbin/pstat
parentf426316829c42690fb184fedff8da5b8ad617f56 (diff)
The number of active vnodes may grow in between the sysctl call
that figures out the size, and the sysctl call that fetches the data. Previously, any growth at all would have resulted in this error message: pstat: sysctl: KERN_VNODE: Cannot allocate memory Now allow for growth of 100 vnodes, or 5%, or both. Growth in excess of 2% or 6000 vnodes has been observed in practice. Also ignore ENOMEM from the second sysctl call, in case the growth was even more than we anticipated.
Diffstat (limited to 'usr.sbin/pstat')
-rw-r--r--usr.sbin/pstat/pstat.c32
1 files changed, 28 insertions, 4 deletions
diff --git a/usr.sbin/pstat/pstat.c b/usr.sbin/pstat/pstat.c
index 459e91fb762..8cbb39163f3 100644
--- a/usr.sbin/pstat/pstat.c
+++ b/usr.sbin/pstat/pstat.c
@@ -1,4 +1,4 @@
-/* $NetBSD: pstat.c,v 1.119 2012/06/04 20:13:47 riastradh Exp $ */
+/* $NetBSD: pstat.c,v 1.120 2012/11/10 11:01:52 apb Exp $ */
/*-
* Copyright (c) 1980, 1991, 1993, 1994
@@ -39,7 +39,7 @@ __COPYRIGHT("@(#) Copyright (c) 1980, 1991, 1993, 1994\
#if 0
static char sccsid[] = "@(#)pstat.c 8.16 (Berkeley) 5/9/95";
#else
-__RCSID("$NetBSD: pstat.c,v 1.119 2012/06/04 20:13:47 riastradh Exp $");
+__RCSID("$NetBSD: pstat.c,v 1.120 2012/11/10 11:01:52 apb Exp $");
#endif
#endif /* not lint */
@@ -73,6 +73,7 @@ __RCSID("$NetBSD: pstat.c,v 1.119 2012/06/04 20:13:47 riastradh Exp $");
#include <sys/sysctl.h>
#include <err.h>
+#include <errno.h>
#include <kvm.h>
#include <limits.h>
#include <nlist.h>
@@ -681,7 +682,8 @@ char *
loadvnodes(int *avnodes)
{
int mib[2];
- size_t copysize;
+ int status;
+ size_t copysize, oldsize;
char *vnodebase;
if (totalflag) {
@@ -696,12 +698,34 @@ loadvnodes(int *avnodes)
}
mib[0] = CTL_KERN;
mib[1] = KERN_VNODE;
+ /*
+ * First sysctl call gets the necessary buffer size; second
+ * sysctl call gets the data. We allow for some growth in the
+ * data size between the two sysctl calls (increases of a few
+ * thousand vnodes in between the two calls have been observed).
+ * We ignore ENOMEM from the second sysctl call, which can
+ * happen if the kernel's data grew by even more than we allowed
+ * for.
+ */
if (sysctl(mib, 2, NULL, &copysize, NULL, 0) == -1)
err(1, "sysctl: KERN_VNODE");
+ oldsize = copysize;
+ copysize += 100 * sizeof(struct vnode) + copysize / 20;
if ((vnodebase = malloc(copysize)) == NULL)
err(1, "malloc");
- if (sysctl(mib, 2, vnodebase, &copysize, NULL, 0) == -1)
+ status = sysctl(mib, 2, vnodebase, &copysize, NULL, 0);
+ if (status == -1 && errno != ENOMEM)
err(1, "sysctl: KERN_VNODE");
+#if 0 /* for debugging the amount of growth allowed for */
+ if (copysize != oldsize) {
+ warnx("count changed from %ld to %ld (%+ld)%s",
+ (long)(oldsize / sizeof(struct vnode)),
+ (long)(copysize / sizeof(struct vnode)),
+ (long)(copysize / sizeof(struct vnode)) -
+ (long)(oldsize / sizeof(struct vnode)),
+ (status == 0 ? "" : ", and errno = ENOMEM"));
+ }
+#endif
if (copysize % (VPTRSZ + VNODESZ))
errx(1, "vnode size mismatch");
*avnodes = copysize / (VPTRSZ + VNODESZ);