misc/110426: rpc.rstatd returns bad info
Bruce Becker
hostmaster at whois.gts.net
Sat Mar 17 07:00:16 UTC 2007
>Number: 110426
>Category: misc
>Synopsis: rpc.rstatd returns bad info
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Sat Mar 17 07:00:11 GMT 2007
>Closed-Date:
>Last-Modified:
>Originator: Bruce Becker
>Release: 4.11
>Organization:
G.T.S.
>Environment:
FreeBSD infra-gw 4.11-STABLE FreeBSD 4.11-STABLE #3: Wed Feb 7 16:21:26 EST 2007 root at infra-gw:/usr/obj/usr/src/sys/FW-YQ i386
>Description:
4.x & 3.x seem to have issues with opackets systcl mib (always returns 0)
this fix uses the kmem interface as well as fixes some code botches
>How-To-Repeat:
view using SunOS/Solaris perfmeter or sysutils/xsysstats port
>Fix:
Patch included
Patch attached with submission follows:
--- rstat_proc.c~ Fri Apr 2 01:56:09 2004
+++ rstat_proc.c Sat Jan 28 22:24:19 2006
@@ -63,7 +63,7 @@
#include <devstat.h>
#include <net/if.h>
-#include <net/if_mib.h>
+#include <net/if_var.h>
#undef FSHIFT /* Use protocol's shift and scale values */
#undef FSCALE
@@ -79,6 +79,8 @@
{ "_cp_time" },
#define X_CNT 1
{ "_cnt" },
+#define X_IFNET 2
+ { "_ifnet" },
{ "" },
};
@@ -87,6 +89,8 @@
void setup __P((void));
int stats_service();
+int firstifnet, numintfs;
+
extern int from_inetd;
int sincelastreq = 0; /* number of alarms since last request */
extern int closedown;
@@ -140,6 +144,7 @@
if (! stat_is_init)
stat_init();
sincelastreq = 0;
+ stats_all.s2.if_opackets = stats_all.s3.if_opackets;
return(&stats_all.s2);
}
@@ -151,6 +156,7 @@
if (! stat_is_init)
stat_init();
sincelastreq = 0;
+ stats_all.s1.if_opackets = stats_all.s3.if_opackets;
return(&stats_all.s1);
}
@@ -187,10 +193,11 @@
void
updatestat()
{
+ long off;
int i, hz;
struct clockinfo clockrate;
struct vmmeter cnt;
- struct ifmibdata ifmd;
+ struct ifnet ifnet;
double avrun[3];
struct timeval tm, btm;
int mib[6];
@@ -229,13 +236,13 @@
exit(1);
}
for(i = 0; i < RSTAT_CPUSTATES ; i++)
- stats_all.s1.cp_time[i] = bsd_cp_time[cp_time_xlat[i]];
+ stats_all.s3.cp_time[i] = bsd_cp_time[cp_time_xlat[i]];
(void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0]));
- stats_all.s2.avenrun[0] = avrun[0] * FSCALE;
- stats_all.s2.avenrun[1] = avrun[1] * FSCALE;
- stats_all.s2.avenrun[2] = avrun[2] * FSCALE;
+ stats_all.s3.avenrun[0] = avrun[0] * FSCALE;
+ stats_all.s3.avenrun[1] = avrun[1] * FSCALE;
+ stats_all.s3.avenrun[2] = avrun[2] * FSCALE;
mib[0] = CTL_KERN;
mib[1] = KERN_BOOTTIME;
@@ -245,13 +252,13 @@
exit(1);
}
- stats_all.s2.boottime.tv_sec = btm.tv_sec;
- stats_all.s2.boottime.tv_usec = btm.tv_usec;
+ stats_all.s3.boottime.tv_sec = btm.tv_sec;
+ stats_all.s3.boottime.tv_usec = btm.tv_usec;
#ifdef DEBUG
- fprintf(stderr, "%d %d %d %d\n", stats_all.s1.cp_time[0],
- stats_all.s1.cp_time[1], stats_all.s1.cp_time[2], stats_all.s1.cp_time[3]);
+ fprintf(stderr, "%d %d %d %d\n", stats_all.s3.cp_time[0],
+ stats_all.s3.cp_time[1], stats_all.s3.cp_time[2], stats_all.s3.cp_time[3]);
#endif
/* XXX - should use sysctl */
@@ -259,54 +266,40 @@
syslog(LOG_ERR, "rstat: can't read cnt from kmem");
exit(1);
}
- stats_all.s1.v_pgpgin = cnt.v_vnodepgsin;
- stats_all.s1.v_pgpgout = cnt.v_vnodepgsout;
- stats_all.s1.v_pswpin = cnt.v_swappgsin;
- stats_all.s1.v_pswpout = cnt.v_swappgsout;
- stats_all.s1.v_intr = cnt.v_intr;
+ stats_all.s3.v_pgpgin = cnt.v_vnodepgsin;
+ stats_all.s3.v_pgpgout = cnt.v_vnodepgsout;
+ stats_all.s3.v_pswpin = cnt.v_swappgsin;
+ stats_all.s3.v_pswpout = cnt.v_swappgsout;
+ stats_all.s3.v_intr = cnt.v_intr;
gettimeofday(&tm, (struct timezone *) 0);
- stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) +
+ stats_all.s3.v_intr -= hz*(tm.tv_sec - btm.tv_sec) +
hz*(tm.tv_usec - btm.tv_usec)/1000000;
- stats_all.s2.v_swtch = cnt.v_swtch;
+ stats_all.s3.v_swtch = cnt.v_swtch;
/* update disk transfers */
- updatexfers(RSTAT_DK_NDRIVE, stats_all.s1.dk_xfer);
+ updatexfers(RSTAT_DK_NDRIVE, stats_all.s3.dk_xfer);
- mib[0] = CTL_NET;
- mib[1] = PF_LINK;
- mib[2] = NETLINK_GENERIC;
- mib[3] = IFMIB_SYSTEM;
- mib[4] = IFMIB_IFCOUNT;
- len = sizeof ifcount;
- if (sysctl(mib, 5, &ifcount, &len, 0, 0) < 0) {
- syslog(LOG_ERR, "sysctl(net.link.generic.system.ifcount): %m");
- exit(1);
- }
-
- stats_all.s1.if_ipackets = 0;
- stats_all.s1.if_opackets = 0;
- stats_all.s1.if_ierrors = 0;
- stats_all.s1.if_oerrors = 0;
- stats_all.s1.if_collisions = 0;
- for (i = 1; i <= ifcount; i++) {
- len = sizeof ifmd;
- mib[3] = IFMIB_IFDATA;
- mib[4] = i;
- mib[5] = IFDATA_GENERAL;
- if (sysctl(mib, 6, &ifmd, &len, 0, 0) < 0) {
- syslog(LOG_ERR, "sysctl(net.link.ifdata.%d.general)"
- ": %m", i);
- exit(1);
+ stats_all.s3.if_ipackets = 0;
+ stats_all.s3.if_opackets = 0;
+ stats_all.s3.if_ierrors = 0;
+ stats_all.s3.if_oerrors = 0;
+ stats_all.s3.if_collisions = 0;
+ for (off = firstifnet, i = 0; off && i < numintfs; i++) {
+ if (kvm_read(kd, off, (char *)&ifnet, sizeof ifnet) != sizeof ifnet) {
+ syslog(LOG_ERR, "can't read ifnet from kmem");
+ exit(1);
+ }
+ stats_all.s3.if_ipackets += ifnet.if_data.ifi_ipackets;
+ stats_all.s3.if_opackets += ifnet.if_data.ifi_opackets;
+ stats_all.s3.if_ierrors += ifnet.if_data.ifi_ierrors;
+ stats_all.s3.if_oerrors += ifnet.if_data.ifi_oerrors;
+ stats_all.s3.if_collisions += ifnet.if_data.ifi_collisions;
+ off = (long)ifnet.if_list.tqe_next;
}
- stats_all.s1.if_ipackets += ifmd.ifmd_data.ifi_ipackets;
- stats_all.s1.if_opackets += ifmd.ifmd_data.ifi_opackets;
- stats_all.s1.if_ierrors += ifmd.ifmd_data.ifi_ierrors;
- stats_all.s1.if_oerrors += ifmd.ifmd_data.ifi_oerrors;
- stats_all.s1.if_collisions += ifmd.ifmd_data.ifi_collisions;
- }
- gettimeofday((struct timeval *)&stats_all.s3.curtime,
- (struct timezone *) 0);
+ gettimeofday(&tm, (struct timezone *) 0);
+ stats_all.s3.curtime.tv_sec = tm.tv_sec;
+ stats_all.s3.curtime.tv_usec = tm.tv_usec;
alarm(1);
}
@@ -314,18 +307,46 @@
setup()
{
char errbuf[_POSIX2_LINE_MAX];
-
int en;
-
- if ((kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf)) == NULL) {
- syslog(LOG_ERR, "rpc.rstatd, %s", errbuf);
- exit(1);
+ struct ifnet ifnet;
+ long off;
+ static int is_kd_setup = 0;
+
+ /* setup() is called after each dormant->active
+ * transition. Since we never close the kvm files
+ * (there's no reason), make sure we don't open them
+ * each time, as that can lead to exhaustion of all open
+ * files! */
+ if (!is_kd_setup) {
+ kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
+ if (kd == NULL) {
+ syslog(LOG_ERR, "%s", errbuf);
+ exit (1);
+ }
+ is_kd_setup = 1;
}
if ((en = kvm_nlist(kd, nl)) != 0) {
syslog(LOG_ERR, "rstatd: Can't get namelist. %d", en);
exit (1);
}
+
+ if (kvm_read(kd, (long)nl[X_IFNET].n_value, &firstifnet,
+ sizeof(int)) != sizeof(int)) {
+ syslog(LOG_ERR, "can't read firstifnet from kmem");
+ exit(1);
+ }
+
+ numintfs = 0;
+ for (off = firstifnet; off;) {
+ if (kvm_read(kd, off, (char *)&ifnet, sizeof ifnet) != sizeof ifnet) {
+ syslog(LOG_ERR, "can't read ifnet from kmem for ifcount");
+ exit(1);
+ }
+ numintfs++;
+ off = (long)ifnet.if_list.tqe_next;
+ }
+
}
/*
@@ -449,7 +470,7 @@
switch (rqstp->rq_proc) {
case NULLPROC:
- (void)svc_sendreply(transp, xdr_void, (char *)NULL);
+ (void)svc_sendreply(transp, (xdrproc_t)xdr_void, (char *)NULL);
goto leave;
case RSTATPROC_STATS:
@@ -497,15 +518,15 @@
goto leave;
}
bzero((char *)&argument, sizeof(argument));
- if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
+ if (!svc_getargs(transp, (xdrproc_t)xdr_argument, (caddr_t)&argument)) {
svcerr_decode(transp);
goto leave;
}
result = (*local)(&argument, rqstp);
- if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
+ if (result != NULL && !svc_sendreply(transp, (xdrproc_t)xdr_result, result)) {
svcerr_systemerr(transp);
}
- if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument))
+ if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, (caddr_t)&argument))
errx(1, "unable to free arguments");
leave:
if (from_inetd)
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list