From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757991Ab3JOAMt (ORCPT ); Mon, 14 Oct 2013 20:12:49 -0400 Received: from mail-pb0-f52.google.com ([209.85.160.52]:58598 "EHLO mail-pb0-f52.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756343Ab3JOAMq (ORCPT ); Mon, 14 Oct 2013 20:12:46 -0400 Date: Mon, 14 Oct 2013 17:12:42 -0700 From: Ning Qu To: Andrea Arcangeli , Andrew Morton , "Kirill A. Shutemov" , Hugh Dickins Cc: Al Viro , Hugh Dickins , Wu Fengguang , Jan Kara , Mel Gorman , linux-mm@kvack.org, Andi Kleen , Matthew Wilcox , Hillf Danton , Dave Hansen , Alexander Shishkin , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, Ning Qu Subject: [PATCH 05/12] mm, thp, tmpfs: request huge page in shm_fault when needed Message-ID: <20131015001242.GF3432@hippobay.mtv.corp.google.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add the function to request huge page in shm_fault when needed. And it will fall back to regular page if huge page can't be satisfied or allocated. If small page requested but huge page is found, the huge page will be splitted. Signed-off-by: Ning Qu --- mm/shmem.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/mm/shmem.c b/mm/shmem.c index 68a0e1d..2fc450d 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1472,19 +1472,45 @@ unlock: static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct inode *inode = file_inode(vma->vm_file); + struct page *page = NULL; int error; int ret = VM_FAULT_LOCKED; gfp_t gfp = mapping_gfp_mask(inode->i_mapping); - - error = shmem_getpage(inode, vmf->pgoff, &vmf->page, SGP_CACHE, gfp, - 0, &ret); + bool must_use_thp = vmf->flags & FAULT_FLAG_TRANSHUGE; + int flags = 0; +#ifdef CONFIG_TRANSPARENT_HUGEPAGE_PAGECACHE + flags |= AOP_FLAG_TRANSHUGE; +#endif +retry_find: + error = shmem_getpage(inode, vmf->pgoff, &page, SGP_CACHE, gfp, + flags, &ret); if (error) return ((error == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS); + /* Split huge page if we don't want huge page to be here */ + if (!must_use_thp && PageTransCompound(page)) { + unlock_page(page); + page_cache_release(page); + split_huge_page(compound_trans_head(page)); + page = NULL; + goto retry_find; + } + + if (must_use_thp && !PageTransHuge(page)) { + /* + * Caller asked for huge page, but we have small page + * by this offset. Fallback to small pages. + */ + unlock_page(page); + page_cache_release(page); + return VM_FAULT_FALLBACK; + } + if (ret & VM_FAULT_MAJOR) { count_vm_event(PGMAJFAULT); mem_cgroup_count_vm_event(vma->vm_mm, PGMAJFAULT); } + vmf->page = page; return ret; } -- 1.8.4