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-head mailing list