From patchwork Tue Nov 24 06:03:40 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Gibson X-Patchwork-Id: 39152 X-Patchwork-Delegate: benh@kernel.crashing.org Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from bilbo.ozlabs.org (localhost [127.0.0.1]) by ozlabs.org (Postfix) with ESMTP id 1E4EB100A24 for ; Tue, 24 Nov 2009 17:03:50 +1100 (EST) Received: by ozlabs.org (Postfix) id 50A091007D3; Tue, 24 Nov 2009 17:03:44 +1100 (EST) Delivered-To: linuxppc-dev@ozlabs.org Received: by ozlabs.org (Postfix, from userid 1007) id 4F15D1007D1; Tue, 24 Nov 2009 17:03:44 +1100 (EST) Date: Tue, 24 Nov 2009 17:03:40 +1100 From: David Gibson To: Benjamin Herrenschmidt Subject: Fix bug in gup_hugepd() Message-ID: <20091124060340.GE2737@yookeroo> Mail-Followup-To: Benjamin Herrenschmidt , linuxppc-dev@ozlabs.org MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.20 (2009-06-14) Cc: linuxppc-dev@ozlabs.org X-BeenThere: linuxppc-dev@lists.ozlabs.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org Errors-To: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org Commit a4fe3ce7699bfe1bd88f816b55d42d8fe1dac655 introduced a new get_user_pages() path for hugepages on powerpc. Unfortunately, there is a bug in it's loop logic, which can cause it to overrun the end of the intended region. This came about by copying the logic from the normal page path, which assumes the address and end parameters have been pagesize aligned at the top-level. Since they're not *hugepage* size aligned, the simplistic logic could step over the end of the gup region without triggering the loop end condition. This patch fixes the bug by using the technique that the normal page path uses in levels above the lowest to truncate the ending address to something we know we'll match with. Signed-off-by: David Gibson Index: working-2.6/arch/powerpc/mm/hugetlbpage.c =================================================================== --- working-2.6.orig/arch/powerpc/mm/hugetlbpage.c 2009-11-24 14:25:36.488330625 +1100 +++ working-2.6/arch/powerpc/mm/hugetlbpage.c 2009-11-24 15:55:27.296455938 +1100 @@ -436,18 +436,27 @@ static noinline int gup_hugepte(pte_t *p return 1; } +static unsigned long hugepte_addr_end(unsigned long addr, unsigned long end, + unsigned long sz) +{ + unsigned long __boundary = (addr + sz) & ~(sz-1); + return (__boundary - 1 < end - 1) ? __boundary : end; +} + int gup_hugepd(hugepd_t *hugepd, unsigned pdshift, unsigned long addr, unsigned long end, int write, struct page **pages, int *nr) { pte_t *ptep; unsigned long sz = 1UL << hugepd_shift(*hugepd); + unsigned long next; ptep = hugepte_offset(hugepd, addr, pdshift); do { + next = hugepte_addr_end(addr, end, sz); if (!gup_hugepte(ptep, sz, addr, end, write, pages, nr)) return 0; - } while (ptep++, addr += sz, addr != end); + } while (ptep++, addr = next, addr != end); return 1; }