Index: sys/compat/linprocfs/linprocfs.c =================================================================== --- sys/compat/linprocfs/linprocfs.c +++ sys/compat/linprocfs/linprocfs.c @@ -469,9 +469,51 @@ return (0); } +/* + * Compare a given Linux kernel version string against + * the system / jail version and returns an integer greater than, equal to, + * or less than zero, according as the version is greater than, equal to, or + * less than the system / jail version. + */ +static int +linprocfs_osrelease_cmp(struct thread *td, const char *rel) +{ + char osrelease[LINUX_MAX_UTSNAME]; + int os_ver[3] = {0, 0, 0}; /* OS kernel version, major, minor */ + int cmp_ver[3] = {0, 0, 0}; /* Compare kernel version, major, minor */ + int i; + + linux_get_osrelease(td, osrelease); + + sscanf(osrelease, "%d.%d.%d", &os_ver[0], &os_ver[1], &os_ver[2]); + sscanf(rel, "%d.%d.%d", &cmp_ver[0], &cmp_ver[1], &cmp_ver[2]); + + for (i = 0; i < 3; i++) { + if (os_ver[i] > cmp_ver[i]) { + return (1); + } else if (os_ver[i] < cmp_ver[i]) { + return (-1); + } + } + + 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 +523,54 @@ long *cp; struct timeval boottime; int i; + char *zero_pad; + bool has_intr = true; + + if (linprocfs_osrelease_cmp(td, "2.6.33") >= 0) { + zero_pad = " 0 0 0 0\n"; + } else if (linprocfs_osrelease_cmp(td, "2.6.24") >= 0) { + zero_pad = " 0 0 0\n"; + } else if (linprocfs_osrelease_cmp(td, "2.6.11") >= 0) { + zero_pad = " 0 0\n"; + } else if (linprocfs_osrelease_cmp(td, "2.5.41") >= 0) { + 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"