Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 8 Aug 2006 18:31:10 GMT
From:      Michael Plass <mfp49_freebsd@plass-family.net>
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   kern/101668: [patch] Some failed calls to contigmalloc(9) cause panic
Message-ID:  <200608081831.k78IVA1q048517@www.freebsd.org>
Resent-Message-ID: <200608081840.k78IeE0L009031@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         101668
>Category:       kern
>Synopsis:       [patch] Some failed calls to contigmalloc(9) cause panic
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Aug 08 18:40:14 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator:     Michael Plass
>Release:        6.1-RELEASE
>Organization:
>Environment:
FreeBSD froghorn 6.1-RELEASE FreeBSD 6.1-RELEASE #0: Sun May  7 04:42:56 UTC 2006     root@opus.cse.buffalo.edu:/usr/obj/usr/src/sys/SMP  i386
>Description:
When contigmalloc(9) is used to request a contiguous physical memory area, a panic can result.  This is most likely to happen in the case of a failed request.

>How-To-Repeat:
A call to contigmalloc that asks for more physical memory than the machine has will cause this panic.  Calls of considerably smaller size can also provoke the problem.

>Fix:
The bug is in vm_page_alloc_contig; the retry logic allows the start value to go negative, so the test (i == -1) in line 437 is incorrect.  The test should be (i < 0):

     63 __FBSDID("$FreeBSD: src/sys/vm/vm_contig.c,v 1.43.2.3.2.1 2006/04/25 15:29:50 scottl Exp $");
    390
    391 vm_page_t
    392 vm_page_alloc_contig(vm_pindex_t npages, vm_paddr_t low, vm_paddr_t high,
    393             vm_offset_t alignment, vm_offset_t boundary)
    394 {
    395         vm_object_t object;
    396         vm_offset_t size;
    397         vm_paddr_t phys;
    398         vm_page_t pga = vm_page_array;
    399         int i, pass, pqtype, start;
    400
    401         size = npages << PAGE_SHIFT;
    402         if (size == 0)
    403                 panic("vm_page_alloc_contig: size must not be 0");
    404         if ((alignment & (alignment - 1)) != 0)
    405                 panic("vm_page_alloc_contig: alignment must be a power of 2");
    406         if ((boundary & (boundary - 1)) != 0)
    407                 panic("vm_page_alloc_contig: boundary must be a power of 2");
    408
    409         for (pass = 0; pass < 2; pass++) {
    410                 if (atop(high) < vm_page_array_size)
    411                         start = atop(high) - npages + 1;
    412                 else
    413                         start = vm_page_array_size - npages + 1;
    414                 vm_page_lock_queues();
    415 retry:
    416                 start--;
    417                 /*
    418                  * Find last page in array that is free, within range,
    419                  * aligned, and such that the boundary won't be crossed.
    420                  */
    421                 for (i = start; i >= 0; i--) {
    422                         phys = VM_PAGE_TO_PHYS(&pga[i]);
    423                         pqtype = pga[i].queue - pga[i].pc;
    424                         if (pass == 0) {
    425                                 if (pqtype != PQ_FREE && pqtype != PQ_CACHE)
    426                                         continue;
    427                         } else if (pqtype != PQ_FREE && pqtype != PQ_CACHE &&
    428                                     pga[i].queue != PQ_ACTIVE &&
    429                                     pga[i].queue != PQ_INACTIVE)
    430                                 continue;
    431                         if (phys >= low && phys + size <= high &&
    432                             ((phys & (alignment - 1)) == 0) &&
    433                             ((phys ^ (phys + size - 1)) & ~(boundary - 1)) == 0)
    434                                 break;
    435                 }
    436                 /* There are no candidates at all. */
****437                 if (i < 0) {
    438                         vm_page_unlock_queues();
    439                         continue;
    440                 }
    441                 start = i;

Here is a patch against -CURRENT:

Index: vm_contig.c
===================================================================
RCS file: /home/ncvs/src/sys/vm/vm_contig.c,v
retrieving revision 1.51
diff -u -r1.51 vm_contig.c
--- vm_contig.c 8 Mar 2006 00:51:00 -0000       1.51
+++ vm_contig.c 8 Aug 2006 18:10:33 -0000
@@ -447,7 +447,7 @@
                                break;
                }
                /* There are no candidates at all. */
-               if (i == -1) {
+               if (i < 0) {
                        vm_page_unlock_queues();
                        continue;
                }

>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200608081831.k78IVA1q048517>