On 09.12.2012 21:35, Alan Cox wrote:
Andre,

I believe that this change did not actually correct the overflow
problem.  See below for an explanation.

On 11/29/2012 01:30, Andre Oppermann wrote:
Author: andre
Date: Thu Nov 29 07:30:42 2012
New Revision: 243668
URL: http://svnweb.freebsd.org/changeset/base/243668

Log:
   Using a long is the wrong type to represent the realmem and maxmbufmem
   variable as they may overflow on i386/PAE and i386 with > 2GB RAM.

   Use 64bit quad_t instead.  It has broader kernel infrastructure support
   with TUNABLE_QUAD_FETCH() and qmin/qmax() than other available types.

   Pointed out by:      alc, bde

Modified:
   head/sys/kern/subr_param.c
   head/sys/sys/mbuf.h

Modified: head/sys/kern/subr_param.c
==============================================================================
--- head/sys/kern/subr_param.c  Thu Nov 29 06:26:42 2012        (r243667)
+++ head/sys/kern/subr_param.c  Thu Nov 29 07:30:42 2012        (r243668)
@@ -93,7 +93,7 @@ int   ncallout;                       /* maximum # of timer ev
  int   nbuf;
  int   ngroups_max;                    /* max # groups per process */
  int   nswbuf;
-long   maxmbufmem;                     /* max mbuf memory */
+quad_t maxmbufmem;                     /* max mbuf memory */
  pid_t pid_max = PID_MAX;
  long  maxswzone;                      /* max swmeta KVA storage */
  long  maxbcache;                      /* max buffer cache KVA storage */
@@ -271,7 +271,7 @@ init_param1(void)
  void
  init_param2(long physpages)
  {
-       long realmem;
+       quad_t realmem;

        /* Base parameters */
        maxusers = MAXUSERS;
@@ -332,10 +332,10 @@ init_param2(long physpages)
         * available kernel memory (physical or kmem).
         * At most it can be 3/4 of available kernel memory.
         */
-       realmem = lmin(physpages * PAGE_SIZE,
+       realmem = qmin(physpages * PAGE_SIZE,
                        VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS);


"physpages" is a signed long.  Suppose it is 1,000,000.  On i386/PAE,
the product of 1,000,000 and PAGE_SIZE will be a negative number.
Likewise, quad_t is a signed type.  So, the negative product of
1,000,000 and PAGE_SIZE will be sign extended to a 64-bit signed value
when it is passed to qmin(), and qmin() will return a negative number.

Thank you taking a second look it.

To be honest I got a bit confused on which automatic type expansion
applies here.

qmax() is defined as this in libkern.h:
static __inline quad_t qmax(quad_t a, quad_t b) { return (a > b ? a : b); }

Wouldn't physpages be expanded to quad_t?  Hmm, no, only the result of the
computation, which happens in long space, is passed on.  This is a function,
not a macro.  Dang...

This change will force the computation to be in quad_t space:

-       realmem = qmin(physpages * PAGE_SIZE,
+       realmem = qmin((quad_t)physpages * PAGE_SIZE,
                        VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS);

VM_[MAX|MIN]_KERNEL_ADDRESS is safe as it is of the unsigned vm_offset_t
type.

--
Andre

        maxmbufmem = realmem / 2;
-       TUNABLE_LONG_FETCH("kern.maxmbufmem", &maxmbufmem);
+       TUNABLE_QUAD_FETCH("kern.maxmbufmem", &maxmbufmem);
        if (maxmbufmem > (realmem / 4) * 3)
                maxmbufmem = (realmem / 4) * 3;


Modified: head/sys/sys/mbuf.h
==============================================================================
--- head/sys/sys/mbuf.h Thu Nov 29 06:26:42 2012        (r243667)
+++ head/sys/sys/mbuf.h Thu Nov 29 07:30:42 2012        (r243668)
@@ -395,7 +395,7 @@ struct mbstat {
   *
   * The rest of it is defined in kern/kern_mbuf.c
   */
-extern long            maxmbufmem;
+extern quad_t          maxmbufmem;
  extern uma_zone_t     zone_mbuf;
  extern uma_zone_t     zone_clust;
  extern uma_zone_t     zone_pack;

D



_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to