diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/page_alloc.c | 20 |
1 files changed, 16 insertions, 4 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index b2d21e06d45d..a8cfa9cc6e86 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -1847,6 +1847,7 @@ __alloc_pages_direct_reclaim(gfp_t gfp_mask, unsigned int order, | |||
1847 | struct page *page = NULL; | 1847 | struct page *page = NULL; |
1848 | struct reclaim_state reclaim_state; | 1848 | struct reclaim_state reclaim_state; |
1849 | struct task_struct *p = current; | 1849 | struct task_struct *p = current; |
1850 | bool drained = false; | ||
1850 | 1851 | ||
1851 | cond_resched(); | 1852 | cond_resched(); |
1852 | 1853 | ||
@@ -1865,14 +1866,25 @@ __alloc_pages_direct_reclaim(gfp_t gfp_mask, unsigned int order, | |||
1865 | 1866 | ||
1866 | cond_resched(); | 1867 | cond_resched(); |
1867 | 1868 | ||
1868 | if (order != 0) | 1869 | if (unlikely(!(*did_some_progress))) |
1869 | drain_all_pages(); | 1870 | return NULL; |
1870 | 1871 | ||
1871 | if (likely(*did_some_progress)) | 1872 | retry: |
1872 | page = get_page_from_freelist(gfp_mask, nodemask, order, | 1873 | page = get_page_from_freelist(gfp_mask, nodemask, order, |
1873 | zonelist, high_zoneidx, | 1874 | zonelist, high_zoneidx, |
1874 | alloc_flags, preferred_zone, | 1875 | alloc_flags, preferred_zone, |
1875 | migratetype); | 1876 | migratetype); |
1877 | |||
1878 | /* | ||
1879 | * If an allocation failed after direct reclaim, it could be because | ||
1880 | * pages are pinned on the per-cpu lists. Drain them and try again | ||
1881 | */ | ||
1882 | if (!page && !drained) { | ||
1883 | drain_all_pages(); | ||
1884 | drained = true; | ||
1885 | goto retry; | ||
1886 | } | ||
1887 | |||
1876 | return page; | 1888 | return page; |
1877 | } | 1889 | } |
1878 | 1890 | ||