From patchwork Thu Oct 27 19:56:54 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Helge Deller X-Patchwork-Id: 9400341 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id BC835600BA for ; Thu, 27 Oct 2016 19:57:17 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A4BC22A2EB for ; Thu, 27 Oct 2016 19:57:17 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 998082A390; Thu, 27 Oct 2016 19:57:17 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,FREEMAIL_FROM, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 576DE2A2EB for ; Thu, 27 Oct 2016 19:57:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S935703AbcJ0T5M (ORCPT ); Thu, 27 Oct 2016 15:57:12 -0400 Received: from mout.gmx.net ([212.227.17.21]:50324 "EHLO mout.gmx.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933171AbcJ0T5L (ORCPT ); Thu, 27 Oct 2016 15:57:11 -0400 Received: from ls3530.box ([92.203.32.222]) by mail.gmx.com (mrgmx103) with ESMTPSA (Nemesis) id 0MNIO5-1bxtvF3yPp-006xl4; Thu, 27 Oct 2016 21:56:57 +0200 Date: Thu, 27 Oct 2016 21:56:54 +0200 From: Helge Deller To: linux-parisc@vger.kernel.org, James Bottomley , John David Anglin Subject: [PATCH] mm, parisc: Optimize unmapped_area_topdown() allocation for bigger alignments Message-ID: <20161027195654.GA31972@ls3530.box> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.23 (2014-03-12) X-Provags-ID: V03:K0:ZWWZ2gDa/RlHuHIt1n0fFa6hC/eGLTaoswL1G3bIkVLjBemAqaS ta9MIn1VrVUznmm9lb9wzY7TLS0KAckHXNM5v4nXxkkoiC6aBiPi5hkbeFRfMlx2UG8/Gqg O9WyH2xiEl3upgOwIGWCVImtgUq0C0XfjnpAt3tEUCC/2V8nqgIU+j+qkJ8skaW+oMr0vpk 6qr5bcpkOfnfsjSceIOrA== X-UI-Out-Filterresults: notjunk:1; V01:K0:wfXifu8IKgI=:GBk7lS5dYsZcs9zDgj7Zyq uoMynHLx1URdR1GxLH8W1GYqtmOaF2CCe53GUg7SXvFw3ejMerSipIJiaXZhs+VPeLnDmn42O DoZYaMhyJePSYLrkd6KayeJTk+JO0GG+Wxbd3kGYMeLo9SeDXVksBHLL9FXry3rVh32BvE0GJ b/lM3iv4VaUBDxbuMqIE1ZYLqkNfbqQTrPdmoH4ToVEGATbyxzTL4OpBtYRd5dHOGjobwGrCL FKuqVk2vJbPgQrrtcrKsJhVFQsjhZjNp1BiwqDrSh9YZZ9aR9harhYrxWerc2RGodSeO7730B AsLjx3YYPc6gQbk9Gg6Fh7OQqbd1GCTRke2DQmaUVL/7J6KdIw3nvnjyyfB8Y7fzf6JeiZPf7 5AT1l6FsuulZ/iKWyMutPFhVP2lNBKUsoP+9nY5chfWiKK6uY28Rcmn21Kq02O8iL4k7sPlT+ qvbqZNgBdcWpOeD6VEAdDjHjhEDNawCOnnJ71fk250IX8zL7ljoplinEKRrZKBmvpaPY4PXEl Er6eIb81WhXWsZWRElV+DtkQ2QCTjiOWjRUJ3IbT4Jh3uJp3k8khAoiYlodjvcPZ7s89IGGBR 3HKRMUCsgImfsRzTBkyHvV6ZvA9Fydo4NTHWfmnHLBkR8z6G9w6v1swtb9LTuPmIcpF7MCqts syaA724l859xUlPn9B1DO7ZLCU6hoMu7tHnCmAjjuEqW7+auLaXn1hFLYuht0NC9JPPwXvjbr qu60m7sAHHi/iqL7jyniN9HN0emy87XG9Rv8eLK9MCLswfxVZYOT/KRHs/c= Sender: linux-parisc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-parisc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP (resending this patch from April 2014 to get it into patchwork) The current implementation of unmapped_area_topdown() is very inefficient for architectures which require an alignment bigger than PAGE_SIZE for shared mappings. This basically affects architectures like parisc, ia64, sparc and probably others. When unmapped_area_topdown() is called to find a free area, the current implementation looks for an area of size (length + align_mask). For many architectures align_mask is 4k (=PAGE_SIZE), while others due to cache colouring require bigger alignment masks of up to 4 MB (e.g. on parisc). In fragmented memory situations this may lead to unmapped_area_topdown() being unable to find even for a few bytes requested a suitable area and as such may return out of memory. This patch modifies the search algorithm to look for an area of the requested size while taking the required alignment and alignment offset into account. Tested on 32- and 64-bit parisc kernels. Signed-off-by: Helge Deller --- To unsubscribe from this list: send the line "unsubscribe linux-parisc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/mm/mmap.c b/mm/mmap.c index 1af87c1..f675e07 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1848,16 +1848,26 @@ unsigned long unmapped_area(struct vm_unmapped_area_info *info) return gap_start; } +/* adjust gap start address upwards to desired alignment */ +static unsigned long gap_start_round_up(unsigned long start, + struct vm_unmapped_area_info *info) +{ + if (!info->align_mask) + return start; + if ((start & info->align_mask) > info->align_offset) + start = ALIGN(start, info->align_mask+1) + info->align_offset; + else + start = (start & ~info->align_mask) + info->align_offset; + return start; +} + unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info) { struct mm_struct *mm = current->mm; struct vm_area_struct *vma; unsigned long length, low_limit, high_limit, gap_start, gap_end; - /* Adjust search length to account for worst case alignment overhead */ - length = info->length + info->align_mask; - if (length < info->length) - return -ENOMEM; + length = info->length; /* * Adjust search limits by the desired length. @@ -1874,8 +1884,10 @@ unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info) /* Check highest gap, which does not precede any rbtree node */ gap_start = mm->highest_vm_end; - if (gap_start <= high_limit) - goto found_highest; + gap_start = gap_start_round_up(gap_start, info); + if (gap_start <= high_limit && gap_end - gap_start >= length && + gap_start < gap_end) + goto found; /* Check if rbtree root looks promising */ if (RB_EMPTY_ROOT(&mm->mm_rb)) @@ -1887,6 +1899,7 @@ unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info) while (true) { /* Visit right subtree if it looks promising */ gap_start = vma->vm_prev ? vma->vm_prev->vm_end : 0; + gap_start = gap_start_round_up(gap_start, info); if (gap_start <= high_limit && vma->vm_rb.rb_right) { struct vm_area_struct *right = rb_entry(vma->vm_rb.rb_right, @@ -1902,7 +1915,8 @@ unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info) gap_end = vma->vm_start; if (gap_end < low_limit) return -ENOMEM; - if (gap_start <= high_limit && gap_end - gap_start >= length) + if (gap_start <= high_limit && gap_end - gap_start >= length && + gap_start < gap_end) goto found; /* Visit left subtree if it looks promising */ @@ -1926,6 +1940,7 @@ unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info) if (prev == vma->vm_rb.rb_right) { gap_start = vma->vm_prev ? vma->vm_prev->vm_end : 0; + gap_start = gap_start_round_up(gap_start, info); goto check_current; } } @@ -1936,7 +1951,6 @@ unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info) if (gap_end > info->high_limit) gap_end = info->high_limit; -found_highest: /* Compute highest gap address at the desired alignment */ gap_end -= info->length; gap_end -= (gap_end - info->align_offset) & info->align_mask;