remove libdss from Makefile
[GitHub/moto-9609/android_kernel_motorola_exynos9610.git] / mm / khugepaged.c
index 43cb3043311bdab1c302955533d7aee137e5b869..d27a73737f1adf0ff255edaf5a67ae03467d0601 100644 (file)
@@ -530,7 +530,12 @@ static int __collapse_huge_page_isolate(struct vm_area_struct *vma,
                        goto out;
                }
 
-               VM_BUG_ON_PAGE(PageCompound(page), page);
+               /* TODO: teach khugepaged to collapse THP mapped with pte */
+               if (PageCompound(page)) {
+                       result = SCAN_PAGE_COMPOUND;
+                       goto out;
+               }
+
                VM_BUG_ON_PAGE(!PageAnon(page), page);
 
                /*
@@ -960,7 +965,9 @@ static void collapse_huge_page(struct mm_struct *mm,
                goto out_nolock;
        }
 
-       if (unlikely(mem_cgroup_try_charge(new_page, mm, gfp, &memcg, true))) {
+       /* Do not oom kill for khugepaged charges */
+       if (unlikely(mem_cgroup_try_charge(new_page, mm, gfp | __GFP_NORETRY,
+                                          &memcg, true))) {
                result = SCAN_CGROUP_CHARGE_FAIL;
                goto out_nolock;
        }
@@ -1281,7 +1288,7 @@ static void retract_page_tables(struct address_space *mapping, pgoff_t pgoff)
  * collapse_shmem - collapse small tmpfs/shmem pages into huge one.
  *
  * Basic scheme is simple, details are more complex:
- *  - allocate and freeze a new huge page;
+ *  - allocate and lock a new huge page;
  *  - scan over radix tree replacing old pages the new one
  *    + swap in pages if necessary;
  *    + fill in gaps;
@@ -1289,11 +1296,11 @@ static void retract_page_tables(struct address_space *mapping, pgoff_t pgoff)
  *  - if replacing succeed:
  *    + copy data over;
  *    + free old pages;
- *    + unfreeze huge page;
+ *    + unlock huge page;
  *  - if replacing failed;
  *    + put all pages back and unfreeze them;
  *    + restore gaps in the radix-tree;
- *    + free huge page;
+ *    + unlock and free huge page;
  */
 static void collapse_shmem(struct mm_struct *mm,
                struct address_space *mapping, pgoff_t start,
@@ -1319,23 +1326,22 @@ static void collapse_shmem(struct mm_struct *mm,
                goto out;
        }
 
-       if (unlikely(mem_cgroup_try_charge(new_page, mm, gfp, &memcg, true))) {
+       /* Do not oom kill for khugepaged charges */
+       if (unlikely(mem_cgroup_try_charge(new_page, mm, gfp | __GFP_NORETRY,
+                                          &memcg, true))) {
                result = SCAN_CGROUP_CHARGE_FAIL;
                goto out;
        }
 
+       __SetPageLocked(new_page);
+       __SetPageSwapBacked(new_page);
        new_page->index = start;
        new_page->mapping = mapping;
-       __SetPageSwapBacked(new_page);
-       __SetPageLocked(new_page);
-       BUG_ON(!page_ref_freeze(new_page, 1));
-
 
        /*
-        * At this point the new_page is 'frozen' (page_count() is zero), locked
-        * and not up-to-date. It's safe to insert it into radix tree, because
-        * nobody would be able to map it or use it in other way until we
-        * unfreeze it.
+        * At this point the new_page is locked and not up-to-date.
+        * It's safe to insert it into the page cache, because nobody would
+        * be able to map it or use it in another way until we unlock it.
         */
 
        index = start;
@@ -1343,19 +1349,29 @@ static void collapse_shmem(struct mm_struct *mm,
        radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) {
                int n = min(iter.index, end) - index;
 
+               /*
+                * Stop if extent has been hole-punched, and is now completely
+                * empty (the more obvious i_size_read() check would take an
+                * irq-unsafe seqlock on 32-bit).
+                */
+               if (n >= HPAGE_PMD_NR) {
+                       result = SCAN_TRUNCATED;
+                       goto tree_locked;
+               }
+
                /*
                 * Handle holes in the radix tree: charge it from shmem and
                 * insert relevant subpage of new_page into the radix-tree.
                 */
                if (n && !shmem_charge(mapping->host, n)) {
                        result = SCAN_FAIL;
-                       break;
+                       goto tree_locked;
                }
-               nr_none += n;
                for (; index < min(iter.index, end); index++) {
                        radix_tree_insert(&mapping->page_tree, index,
                                        new_page + (index % HPAGE_PMD_NR));
                }
+               nr_none += n;
 
                /* We are done. */
                if (index >= end)
@@ -1371,12 +1387,12 @@ static void collapse_shmem(struct mm_struct *mm,
                                result = SCAN_FAIL;
                                goto tree_unlocked;
                        }
-                       spin_lock_irq(&mapping->tree_lock);
                } else if (trylock_page(page)) {
                        get_page(page);
+                       spin_unlock_irq(&mapping->tree_lock);
                } else {
                        result = SCAN_PAGE_LOCK;
-                       break;
+                       goto tree_locked;
                }
 
                /*
@@ -1385,17 +1401,24 @@ static void collapse_shmem(struct mm_struct *mm,
                 */
                VM_BUG_ON_PAGE(!PageLocked(page), page);
                VM_BUG_ON_PAGE(!PageUptodate(page), page);
-               VM_BUG_ON_PAGE(PageTransCompound(page), page);
+
+               /*
+                * If file was truncated then extended, or hole-punched, before
+                * we locked the first page, then a THP might be there already.
+                */
+               if (PageTransCompound(page)) {
+                       result = SCAN_PAGE_COMPOUND;
+                       goto out_unlock;
+               }
 
                if (page_mapping(page) != mapping) {
                        result = SCAN_TRUNCATED;
                        goto out_unlock;
                }
-               spin_unlock_irq(&mapping->tree_lock);
 
                if (isolate_lru_page(page)) {
                        result = SCAN_DEL_PAGE_LRU;
-                       goto out_isolate_failed;
+                       goto out_unlock;
                }
 
                if (page_mapped(page))
@@ -1417,7 +1440,9 @@ static void collapse_shmem(struct mm_struct *mm,
                 */
                if (!page_ref_freeze(page, 3)) {
                        result = SCAN_PAGE_COUNT;
-                       goto out_lru;
+                       spin_unlock_irq(&mapping->tree_lock);
+                       putback_lru_page(page);
+                       goto out_unlock;
                }
 
                /*
@@ -1433,17 +1458,10 @@ static void collapse_shmem(struct mm_struct *mm,
                slot = radix_tree_iter_resume(slot, &iter);
                index++;
                continue;
-out_lru:
-               spin_unlock_irq(&mapping->tree_lock);
-               putback_lru_page(page);
-out_isolate_failed:
-               unlock_page(page);
-               put_page(page);
-               goto tree_unlocked;
 out_unlock:
                unlock_page(page);
                put_page(page);
-               break;
+               goto tree_unlocked;
        }
 
        /*
@@ -1451,14 +1469,18 @@ out_unlock:
         * This code only triggers if there's nothing in radix tree
         * beyond 'end'.
         */
-       if (result == SCAN_SUCCEED && index < end) {
+       if (index < end) {
                int n = end - index;
 
+               /* Stop if extent has been truncated, and is now empty */
+               if (n >= HPAGE_PMD_NR) {
+                       result = SCAN_TRUNCATED;
+                       goto tree_locked;
+               }
                if (!shmem_charge(mapping->host, n)) {
                        result = SCAN_FAIL;
                        goto tree_locked;
                }
-
                for (; index < end; index++) {
                        radix_tree_insert(&mapping->page_tree, index,
                                        new_page + (index % HPAGE_PMD_NR));
@@ -1466,57 +1488,62 @@ out_unlock:
                nr_none += n;
        }
 
+       __inc_node_page_state(new_page, NR_SHMEM_THPS);
+       if (nr_none) {
+               struct zone *zone = page_zone(new_page);
+
+               __mod_node_page_state(zone->zone_pgdat, NR_FILE_PAGES, nr_none);
+               __mod_node_page_state(zone->zone_pgdat, NR_SHMEM, nr_none);
+       }
+
 tree_locked:
        spin_unlock_irq(&mapping->tree_lock);
 tree_unlocked:
 
        if (result == SCAN_SUCCEED) {
-               unsigned long flags;
-               struct zone *zone = page_zone(new_page);
-
                /*
                 * Replacing old pages with new one has succeed, now we need to
                 * copy the content and free old pages.
                 */
+               index = start;
                list_for_each_entry_safe(page, tmp, &pagelist, lru) {
+                       while (index < page->index) {
+                               clear_highpage(new_page + (index % HPAGE_PMD_NR));
+                               index++;
+                       }
                        copy_highpage(new_page + (page->index % HPAGE_PMD_NR),
                                        page);
                        list_del(&page->lru);
-                       unlock_page(page);
-                       page_ref_unfreeze(page, 1);
                        page->mapping = NULL;
+                       page_ref_unfreeze(page, 1);
                        ClearPageActive(page);
                        ClearPageUnevictable(page);
+                       unlock_page(page);
                        put_page(page);
+                       index++;
                }
-
-               local_irq_save(flags);
-               __inc_node_page_state(new_page, NR_SHMEM_THPS);
-               if (nr_none) {
-                       __mod_node_page_state(zone->zone_pgdat, NR_FILE_PAGES, nr_none);
-                       __mod_node_page_state(zone->zone_pgdat, NR_SHMEM, nr_none);
+               while (index < end) {
+                       clear_highpage(new_page + (index % HPAGE_PMD_NR));
+                       index++;
                }
-               local_irq_restore(flags);
 
-               /*
-                * Remove pte page tables, so we can re-faulti
-                * the page as huge.
-                */
-               retract_page_tables(mapping, start);
-
-               /* Everything is ready, let's unfreeze the new_page */
-               set_page_dirty(new_page);
                SetPageUptodate(new_page);
-               page_ref_unfreeze(new_page, HPAGE_PMD_NR);
+               page_ref_add(new_page, HPAGE_PMD_NR - 1);
+               set_page_dirty(new_page);
                mem_cgroup_commit_charge(new_page, memcg, false, true);
                lru_cache_add_anon(new_page);
-               unlock_page(new_page);
 
+               /*
+                * Remove pte page tables, so we can re-fault the page as huge.
+                */
+               retract_page_tables(mapping, start);
                *hpage = NULL;
        } else {
                /* Something went wrong: rollback changes to the radix-tree */
-               shmem_uncharge(mapping->host, nr_none);
                spin_lock_irq(&mapping->tree_lock);
+               mapping->nrpages -= nr_none;
+               shmem_uncharge(mapping->host, nr_none);
+
                radix_tree_for_each_slot(slot, &mapping->page_tree, &iter,
                                start) {
                        if (iter.index >= end)
@@ -1542,19 +1569,18 @@ tree_unlocked:
                                                slot, page);
                        slot = radix_tree_iter_resume(slot, &iter);
                        spin_unlock_irq(&mapping->tree_lock);
-                       putback_lru_page(page);
                        unlock_page(page);
+                       putback_lru_page(page);
                        spin_lock_irq(&mapping->tree_lock);
                }
                VM_BUG_ON(nr_none);
                spin_unlock_irq(&mapping->tree_lock);
 
-               /* Unfreeze new_page, caller would take care about freeing it */
-               page_ref_unfreeze(new_page, 1);
                mem_cgroup_cancel_charge(new_page, memcg, true);
-               unlock_page(new_page);
                new_page->mapping = NULL;
        }
+
+       unlock_page(new_page);
 out:
        VM_BUG_ON(!list_empty(&pagelist));
        /* TODO: tracepoints */
@@ -1674,10 +1700,14 @@ static unsigned int khugepaged_scan_mm_slot(unsigned int pages,
        spin_unlock(&khugepaged_mm_lock);
 
        mm = mm_slot->mm;
-       down_read(&mm->mmap_sem);
-       if (unlikely(khugepaged_test_exit(mm)))
-               vma = NULL;
-       else
+       /*
+        * Don't wait for semaphore (to avoid long wait times).  Just move to
+        * the next mm on the list.
+        */
+       vma = NULL;
+       if (unlikely(!down_read_trylock(&mm->mmap_sem)))
+               goto breakouterloop_mmap_sem;
+       if (likely(!khugepaged_test_exit(mm)))
                vma = find_vma(mm, khugepaged_scan.address);
 
        progress++;