Date: Thu, 8 Nov 2012 21:41:29 +1100 (EST) From: Bruce Evans <brde@optusnet.com.au> To: Marius Strobl <marius@freebsd.org> Cc: svn-src-head@freebsd.org, svn-src-all@freebsd.org, src-committers@freebsd.org Subject: Re: svn commit: r242747 - head/sys/kern Message-ID: <20121108205636.O3941@besplex.bde.org> In-Reply-To: <201211080810.qA88AW8Y027373@svn.freebsd.org> References: <201211080810.qA88AW8Y027373@svn.freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On Thu, 8 Nov 2012, Marius Strobl wrote: > Log: > Make r242655 build on sparc64. While at it, make vm_{max,min}_kernel_address > vm_offset_t as they should be. Er, they shouldn't be vm_offset_t. > Modified: head/sys/kern/kern_malloc.c > ============================================================================== > --- head/sys/kern/kern_malloc.c Thu Nov 8 04:02:36 2012 (r242746) > +++ head/sys/kern/kern_malloc.c Thu Nov 8 08:10:32 2012 (r242747) > @@ -186,11 +186,13 @@ struct { > */ > static uma_zone_t mt_zone; > > -static u_long vm_min_kernel_address = VM_MIN_KERNEL_ADDRESS; > +static vm_offset_t vm_min_kernel_address = VM_MIN_KERNEL_ADDRESS; > SYSCTL_ULONG(_vm, OID_AUTO, min_kernel_address, CTLFLAG_RD, > &vm_min_kernel_address, 0, "Min kernel address"); SYSCTL_ULONG takes a u_long, not a vm_offset_t. A cast in SYSCTL_ULONG() prevents possible detection of the type mismatch from this. This is most broken on i386's with correctly-sized longs (or almost any arch with correctly-sized longs). There, vm_offset_t is 1 register wide and longs are 2 registers wide. The bugs could be moved using SYSCTL_QUAD(). Correctly-sized quads would be 4 registers wide, except quad has come to mean just a bad way of spelling long long or int64_t. > -static u_long vm_max_kernel_address = VM_MAX_KERNEL_ADDRESS; > +#ifndef __sparc64__ > +static vm_offset_t vm_max_kernel_address = VM_MAX_KERNEL_ADDRESS; > +#endif > SYSCTL_ULONG(_vm, OID_AUTO, max_kernel_address, CTLFLAG_RD, > &vm_max_kernel_address, 0, "Max kernel address"); Since the value is a compile-time constant, u_long has a chance of holding its value even if u_long != vm_offset_t, and the old code is closer to being correct than first appeared, and the correct fix is relatively easy -- just use a uintmax_t vatiable and SYSCTL_UINTMAX() (*). Unfortunately SYSCT_UINTMAX() doesn't exist, and the bogus SYSCTL_UQUAD() does exist. (*) Except a temporary variable is just a style bug in the above and for this. SYSCTL_UNLONG(), like all integer SYSCTL()'s, has the feature of supporting either a variable or a constant arg. The above should use a constant arg and not need a variable. IIRC, the syntax for this is: SYSCTL_ULONG(_vm, OID_AUTO, max_kernel_address, CTLFLAG_RD, NULL, VM_MAX_KERNEL_ADDRESS, "Max kernel address"); subr_param.c is careful to use only basic types for all of its variables so that standard sysctls apply. Tunables have even more bugs in this area: at least at the input level kern_environment.c: - bogus quads are supported, but bogus uquads aren't - everything goes through getenv_quad(), which uses strtoq(), which is for signed values, so unsigned values are mishandled in various ways - worst sign bugs are on 64-bit arches. getenv_ulong() uses getenv_quad(), with blind casts and no overflow checking, so 64-bit values are silently truncated to QUAD_MAX (63 bits). Before that, getenv_quad() has overflow checking in its strtoq() call, but none in its multiplication, and the API is broken (strtoq(3) indicatates errors in errno, but there is no errno in the kernel). The bugs in tunables mean that sysctls that report read-only tunables can safely use SYSCTL_QUAD(). This is hard to fix cleanly without combinatorial explosion in the number of types, giving uglyness in the implementation. It is probably best to have single SYSCTL_INT() that operates on all integral types (signed and unsigned) according to its the arg type. E.g.: static vm_offset_t vm_min_kernel_address = VM_MIN_KERNEL_ADDRESS; SYSCTL_INT(_vm, OID_AUTO, min_kernel_address, CTLFLAG_RD, &vm_min_kernel_address, 0, "Min kernel address"); This should expand to an uncast &vm_min_kernel_address, with auxilary data for the size and sign of that. sysctl_handle_int() should operate atomically on all integer sizes according to the size and sign info. Some SYSCTL_FOO()'s already generate size info or take a size arg, but sysctl_handle_int() only supports plain int and is abused to support u_int and is sometimes misused on sysctl data that has a size. After fixing the style bug: SYSCTL_INT(_vm, OID_AUTO, min_kernel_address, CTLFLAG_RD, NULL, VM_MIN_KERNEL_ADDRESS, "Min kernel address"); The constant can have any integral type, and a the sysctl must generate size and sign info for it too. The API can probably be simplified to reduce the 2 parameters to 1. Hopefully __builtin_constant_p() can be used to decide which case applies. Bruce
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20121108205636.O3941>