Fix output of linprocfs stat entry

The Linux /proc/stat entry has grown over time

 v2.5.41 <
   user, nice, system, idle
 v2.5.41
   user, nice, system, idle, iowait, irq
 v2.6.11
   user, nice, system, idle, iowait, irq, softirq, steal
 v2.6.24
   user, nice, system, idle, iowait, irq, softirq, steal, guest
 v2.6.32 >
   user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice

Some applications (e.g. nodejs) depend on the correct number of entries
and will abort otherwise.

Fix is to print the correct number of entries based on the value of
osrelease set either in sysctl or the jail settings. Change is similar
to approach used by illumos.

Reviewed by: emaste, imp (mentor)
Approved by: imp (mentor)
Differential Revision: https://reviews.freebsd.org/D15858
This commit is contained in:
Chuck Tuffli 2018-06-22 00:02:05 +00:00
parent 3575504976
commit 4c4317193b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=335516

View File

@ -469,9 +469,21 @@ linprocfs_dopartitions(PFS_FILL_ARGS)
return (0);
}
/*
* Filler function for proc/stat
*
* Output depends on kernel version:
*
* v2.5.40 <=
* user nice system idle
* v2.5.41
* user nice system idle iowait
* v2.6.11
* user nice system idle iowait irq softirq steal
* v2.6.24
* user nice system idle iowait irq softirq steal guest
* v2.6.33 >=
* user nice system idle iowait irq softirq steal guest guest_nice
*/
static int
linprocfs_dostat(PFS_FILL_ARGS)
@ -481,22 +493,54 @@ linprocfs_dostat(PFS_FILL_ARGS)
long *cp;
struct timeval boottime;
int i;
char *zero_pad;
bool has_intr = true;
if (linux_kernver(td) >= LINUX_KERNVER(2,6,33)) {
zero_pad = " 0 0 0 0\n";
} else if (linux_kernver(td) >= LINUX_KERNVER(2,6,24)) {
zero_pad = " 0 0 0\n";
} else if (linux_kernver(td) >= LINUX_KERNVER(2,6,11)) {
zero_pad = " 0 0\n";
} else if (linux_kernver(td) >= LINUX_KERNVER(2,5,41)) {
has_intr = false;
zero_pad = " 0\n";
} else {
has_intr = false;
zero_pad = "\n";
}
read_cpu_time(cp_time);
getboottime(&boottime);
sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
/* Parameters common to all versions */
sbuf_printf(sb, "cpu %lu %lu %lu %lu",
T2J(cp_time[CP_USER]),
T2J(cp_time[CP_NICE]),
T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
T2J(cp_time[CP_SYS]),
T2J(cp_time[CP_IDLE]));
/* Print interrupt stats if available */
if (has_intr) {
sbuf_printf(sb, " 0 %lu", T2J(cp_time[CP_INTR]));
}
/* Pad out remaining fields depending on version */
sbuf_printf(sb, "%s", zero_pad);
CPU_FOREACH(i) {
pcpu = pcpu_find(i);
cp = pcpu->pc_cp_time;
sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
sbuf_printf(sb, "cpu%d %lu %lu %lu %lu", i,
T2J(cp[CP_USER]),
T2J(cp[CP_NICE]),
T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
T2J(cp[CP_SYS]),
T2J(cp[CP_IDLE]));
if (has_intr) {
sbuf_printf(sb, " 0 %lu", T2J(cp[CP_INTR]));
}
sbuf_printf(sb, "%s", zero_pad);
}
sbuf_printf(sb,
"disk 0 0 0 0\n"