mm: soft offline: split thp at the beginning of soft_offline_page()
[platform/adaptation/renesas_rcar/renesas_kernel.git] / mm / memory-failure.c
index a6e2141..8b20278 100644 (file)
@@ -400,18 +400,21 @@ static void collect_procs_anon(struct page *page, struct list_head *to_kill,
        struct vm_area_struct *vma;
        struct task_struct *tsk;
        struct anon_vma *av;
+       pgoff_t pgoff;
 
        av = page_lock_anon_vma(page);
        if (av == NULL) /* Not actually mapped anymore */
                return;
 
+       pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
        read_lock(&tasklist_lock);
        for_each_process (tsk) {
                struct anon_vma_chain *vmac;
 
                if (!task_early_kill(tsk))
                        continue;
-               list_for_each_entry(vmac, &av->head, same_anon_vma) {
+               anon_vma_interval_tree_foreach(vmac, &av->rb_root,
+                                              pgoff, pgoff) {
                        vma = vmac->vma;
                        if (!page_mapped_in_vma(page, vma))
                                continue;
@@ -431,7 +434,6 @@ static void collect_procs_file(struct page *page, struct list_head *to_kill,
 {
        struct vm_area_struct *vma;
        struct task_struct *tsk;
-       struct prio_tree_iter iter;
        struct address_space *mapping = page->mapping;
 
        mutex_lock(&mapping->i_mmap_mutex);
@@ -442,7 +444,7 @@ static void collect_procs_file(struct page *page, struct list_head *to_kill,
                if (!task_early_kill(tsk))
                        continue;
 
-               vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff,
+               vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff,
                                      pgoff) {
                        /*
                         * Send early kill signal to tasks where a vma covers
@@ -1474,9 +1476,17 @@ int soft_offline_page(struct page *page, int flags)
 {
        int ret;
        unsigned long pfn = page_to_pfn(page);
+       struct page *hpage = compound_trans_head(page);
 
        if (PageHuge(page))
                return soft_offline_huge_page(page, flags);
+       if (PageTransHuge(hpage)) {
+               if (PageAnon(hpage) && unlikely(split_huge_page(hpage))) {
+                       pr_info("soft offline: %#lx: failed to split THP\n",
+                               pfn);
+                       return -EBUSY;
+               }
+       }
 
        ret = get_any_page(page, pfn, flags);
        if (ret < 0)