From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S262035AbUDHQcQ (ORCPT ); Thu, 8 Apr 2004 12:32:16 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S262060AbUDHQcQ (ORCPT ); Thu, 8 Apr 2004 12:32:16 -0400 Received: from pub236.cambridge.redhat.com ([213.86.99.236]:31735 "EHLO warthog.cambridge.redhat.com") by vger.kernel.org with ESMTP id S262035AbUDHQcJ (ORCPT ); Thu, 8 Apr 2004 12:32:09 -0400 From: David Howells To: Andrew Morton , Linus Torvalds Cc: linux-kernel@vger.kernel.org Subject: [PATCH] order>0 page freeing bug User-Agent: EMH/1.14.1 SEMI/1.14.4 (Hosorogi) FLIM/1.14.5 (Demachiyanagi) APEL/10.6 Emacs/21.3 (i386-redhat-linux-gnu) MULE/5.0 (SAKAKI) MIME-Version: 1.0 (generated by SEMI 1.14.4 - "Hosorogi") Content-Type: text/plain; charset=US-ASCII Date: Thu, 08 Apr 2004 17:31:57 +0100 Message-ID: <5213.1081441917@redhat.com> Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org Hi Andrew, Linus, Here's a patch to fix a bug that occurs when an order>0 page allocation is freed. The bug can be demonstrated by this example: (1) if __alloc_page() returns an order 1 allocation, you get back two pages, both with count == 1 (2) __free_pages() only decrements the counter on the first page (3) __free_pages_ok() calls free_pages_check() on both pages (4) free_pages_check() complains that the second page is a bad_page because its count is not 0 at that point. David diff -ur /inst-kernels/linux-2.6.5-rc3/mm/page_alloc.c linux-2.6.5-rc3-new/mm/page_alloc.c --- /inst-kernels/linux-2.6.5-rc3/mm/page_alloc.c 2004-03-31 14:54:23.000000000 +0100 +++ linux-2.6.5-rc3-new/mm/page_alloc.c 2004-04-08 17:18:13.000000000 +0100 @@ -269,8 +269,12 @@ int i; mod_page_state(pgfree, 1 << order); - for (i = 0 ; i < (1 << order) ; ++i) + free_pages_check(__FUNCTION__, page); + for (i = 1 ; i < (1 << order) ; ++i) { + if (unlikely(!atomic_dec_and_test(&page[i].count))) + BUG(); free_pages_check(__FUNCTION__, page + i); + } list_add(&page->list, &list); kernel_map_pages(page, 1<