mm,shmem,thp: limit shmem THP allocations to requested zones
[linux-2.6-microblaze.git] / mm / shmem.c
index ee8f218..b2db4ed 100644 (file)
@@ -1505,6 +1505,30 @@ static struct page *shmem_swapin(swp_entry_t swap, gfp_t gfp,
        return page;
 }
 
+/*
+ * Make sure huge_gfp is always more limited than limit_gfp.
+ * Some of the flags set permissions, while others set limitations.
+ */
+static gfp_t limit_gfp_mask(gfp_t huge_gfp, gfp_t limit_gfp)
+{
+       gfp_t allowflags = __GFP_IO | __GFP_FS | __GFP_RECLAIM;
+       gfp_t denyflags = __GFP_NOWARN | __GFP_NORETRY;
+       gfp_t zoneflags = limit_gfp & GFP_ZONEMASK;
+       gfp_t result = huge_gfp & ~(allowflags | GFP_ZONEMASK);
+
+       /* Allow allocations only from the originally specified zones. */
+       result |= zoneflags;
+
+       /*
+        * Minimize the result gfp by taking the union with the deny flags,
+        * and the intersection of the allow flags.
+        */
+       result |= (limit_gfp & denyflags);
+       result |= (huge_gfp & limit_gfp) & allowflags;
+
+       return result;
+}
+
 static struct page *shmem_alloc_hugepage(gfp_t gfp,
                struct shmem_inode_info *info, pgoff_t index)
 {
@@ -1519,8 +1543,8 @@ static struct page *shmem_alloc_hugepage(gfp_t gfp,
                return NULL;
 
        shmem_pseudo_vma_init(&pvma, info, hindex);
-       page = alloc_pages_vma(gfp | __GFP_COMP | __GFP_NORETRY | __GFP_NOWARN,
-                       HPAGE_PMD_ORDER, &pvma, 0, numa_node_id(), true);
+       page = alloc_pages_vma(gfp, HPAGE_PMD_ORDER, &pvma, 0, numa_node_id(),
+                              true);
        shmem_pseudo_vma_destroy(&pvma);
        if (page)
                prep_transhuge_page(page);
@@ -1776,6 +1800,7 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t index,
        struct page *page;
        enum sgp_type sgp_huge = sgp;
        pgoff_t hindex = index;
+       gfp_t huge_gfp;
        int error;
        int once = 0;
        int alloced = 0;
@@ -1862,7 +1887,9 @@ repeat:
        }
 
 alloc_huge:
-       page = shmem_alloc_and_acct_page(gfp, inode, index, true);
+       huge_gfp = vma_thp_gfp_mask(vma);
+       huge_gfp = limit_gfp_mask(huge_gfp, gfp);
+       page = shmem_alloc_and_acct_page(huge_gfp, inode, index, true);
        if (IS_ERR(page)) {
 alloc_nohuge:
                page = shmem_alloc_and_acct_page(gfp, inode,