svn commit: r317231 - head/usr.bin/systat
Bruce Evans
brde at optusnet.com.au
Fri Apr 21 14:22:31 UTC 2017
On Fri, 21 Apr 2017, Bruce Evans wrote:
> On Thu, 20 Apr 2017, Jung-uk Kim wrote:
>
>> Log:
>> Fix systat(1) regression. It was broken by r317061.
>
> It is more broken than before. Now it fails when the kernel is older
> than the utility instead of vice versa. When it fails, the failures
> are more serious than before. systat -v actually does complete
> checking for errors (some are only errors in itself), but mishandles
> them. It reports the errors on the status line and continues. The
> error message overwrites the previous one. Continuing is more broken
> than before:
The follow patch reduces the ABI breakage as much as possible. On a
lightly loaded system, the maximum value in any counter used by top,
vmstat or systat -v is growing at a rate of 1M per hour, so the 32-bit
variables in the application are enough for about 166 days.
I only applied the fix to some counter sysctls with broken ABIs, but
wrote it for general use. It doesn't handle SYSCTL_IN(), and assumes
unsigned counters.
X Index: subr_counter.c
X ===================================================================
X --- subr_counter.c (revision 317243)
X +++ subr_counter.c (working copy)
X @@ -74,6 +75,95 @@
X uma_zfree(pcpu_zone_64, c);
X }
X
X +/* Output a signed integer with the caller's size as well as possible. */
X +__unused
X +static int
X +sysctl_out_i(struct sysctl_req *req, intmax_t val)
X +{
X + intmax_t valtrunc;
X + int64_t val64;
X + int32_t val32;
X + int16_t val16;
X + int8_t val8;
X + int error;
X +
X + switch (req->oldlen) {
X + case 1:
X + valtrunc = val8 = val;
X + error = SYSCTL_OUT(req, &val8, 1);
X + break;
X + case 2:
X + valtrunc = val16 = val;
X + error = SYSCTL_OUT(req, &val16, 2);
X + break;
X + case 4:
X + valtrunc = val32 = val;
X + error = SYSCTL_OUT(req, &val32, 4);
X + break;
X + case 8:
X + valtrunc = val64 = val;
X + error = SYSCTL_OUT(req, &val64, 8);
X + break;
X + default:
X + valtrunc = val;
X + error = SYSCTL_OUT(req, &val, sizeof(val));
X + break;
X + }
X + if (valtrunc != val && error == 0)
X + error = EOVERFLOW;
X + return (error);
X +}
X +
X +uintmax_t sysoui_max;
X +
X +/* Output an unsigned integer with the caller's size as well as possible. */
X +static int
X +sysctl_out_ui(struct sysctl_req *req, uintmax_t val)
X +{
X + uintmax_t valtrunc;
X + uint64_t val64;
X + uint32_t val32;
X + uint16_t val16;
X + uint8_t val8;
X + int error;
X +
X + if (sysoui_max < val) {
X + sysoui_max = val;
X + if ((val & 0xffff) == 0)
X + printf("new sysoui_max %#jx\n", val);
X + }
X + val64 = val32 = val16 = val8 = 0;
X + switch (req->oldlen) {
X + case 1:
X + valtrunc = val8 = val;
X + error = SYSCTL_OUT(req, &val8, 1);
X + break;
X + case 2:
X + valtrunc = val16 = val;
X + error = SYSCTL_OUT(req, &val16, 2);
X + break;
X + case 4:
X + valtrunc = val32 = val;
X + error = SYSCTL_OUT(req, &val32, 4);
X + break;
X + case 8:
X + valtrunc = val64 = val;
X + error = SYSCTL_OUT(req, &val64, 8);
X + break;
X + default:
X + valtrunc = val;
X + error = SYSCTL_OUT(req, &val, sizeof(val));
X + break;
X + }
X + if (valtrunc != val && error == 0) {
X + printf(
X + "val %#jx, valtrunc %#jx, val64 %#jx, val32 %#x, val16 %#x, val8 %#x\n",
X + val, valtrunc, val64, val32, val16, val8);
X + error = EOVERFLOW;
X + }
X + return (error);
X +}
X +
X int
X sysctl_handle_counter_u64(SYSCTL_HANDLER_ARGS)
X {
X @@ -82,7 +172,7 @@
X
X out = counter_u64_fetch(*(counter_u64_t *)arg1);
X
X - error = SYSCTL_OUT(req, &out, sizeof(uint64_t));
X + error = sysctl_out_ui(req, out);
X
X if (error || !req->newptr)
X return (error);
Bruce
More information about the svn-src-all
mailing list