tools headers UAPI: Sync linux/prctl.h with the kernel sources
[linux-2.6-microblaze.git] / mm / rmap.c
index 08c56aa..693a610 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -168,7 +168,7 @@ static void anon_vma_chain_link(struct vm_area_struct *vma,
  *
  * Anon-vma allocations are very subtle, because we may have
  * optimistically looked up an anon_vma in page_lock_anon_vma_read()
- * and that may actually touch the spinlock even in the newly
+ * and that may actually touch the rwsem even in the newly
  * allocated vma (it depends on RCU to make sure that the
  * anon_vma isn't actually destroyed).
  *
@@ -257,7 +257,7 @@ static inline void unlock_anon_vma_root(struct anon_vma *root)
  * Attach the anon_vmas from src to dst.
  * Returns 0 on success, -ENOMEM on failure.
  *
- * anon_vma_clone() is called by __vma_split(), __split_vma(), copy_vma() and
+ * anon_vma_clone() is called by __vma_adjust(), __split_vma(), copy_vma() and
  * anon_vma_fork(). The first three want an exact copy of src, while the last
  * one, anon_vma_fork(), may try to reuse an existing anon_vma to prevent
  * endless growth of anon_vma. Since dst->anon_vma is set to NULL before call,
@@ -359,7 +359,7 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma)
                goto out_error_free_anon_vma;
 
        /*
-        * The root anon_vma's spinlock is the lock actually used when we
+        * The root anon_vma's rwsem is the lock actually used when we
         * lock any of the anon_vmas in this anon_vma tree.
         */
        anon_vma->root = pvma->anon_vma->root;
@@ -413,8 +413,15 @@ void unlink_anon_vmas(struct vm_area_struct *vma)
                list_del(&avc->same_vma);
                anon_vma_chain_free(avc);
        }
-       if (vma->anon_vma)
+       if (vma->anon_vma) {
                vma->anon_vma->degree--;
+
+               /*
+                * vma would still be needed after unlink, and anon_vma will be prepared
+                * when handle fault.
+                */
+               vma->anon_vma = NULL;
+       }
        unlock_anon_vma_root(root);
 
        /*
@@ -455,8 +462,8 @@ void __init anon_vma_init(void)
  * Getting a lock on a stable anon_vma from a page off the LRU is tricky!
  *
  * Since there is no serialization what so ever against page_remove_rmap()
- * the best this function can do is return a locked anon_vma that might
- * have been relevant to this page.
+ * the best this function can do is return a refcount increased anon_vma
+ * that might have been relevant to this page.
  *
  * The page might have been remapped to a different anon_vma or the anon_vma
  * returned may already be freed (and even reused).
@@ -1079,8 +1086,7 @@ static void __page_check_anon_rmap(struct page *page,
         * be set up correctly at this point.
         *
         * We have exclusion against page_add_anon_rmap because the caller
-        * always holds the page locked, except if called from page_dup_rmap,
-        * in which case the page is already known to be setup.
+        * always holds the page locked.
         *
         * We have exclusion against page_add_new_anon_rmap because those pages
         * are initially only visible via the pagetables, and the pte is locked
@@ -1144,7 +1150,7 @@ void do_page_add_anon_rmap(struct page *page,
                 * disabled.
                 */
                if (compound)
-                       __inc_lruvec_page_state(page, NR_ANON_THPS);
+                       __mod_lruvec_page_state(page, NR_ANON_THPS, nr);
                __mod_lruvec_page_state(page, NR_ANON_MAPPED, nr);
        }
 
@@ -1186,7 +1192,7 @@ void page_add_new_anon_rmap(struct page *page,
                if (hpage_pincount_available(page))
                        atomic_set(compound_pincount_ptr(page), 0);
 
-               __inc_lruvec_page_state(page, NR_ANON_THPS);
+               __mod_lruvec_page_state(page, NR_ANON_THPS, nr);
        } else {
                /* Anon THP always mapped first with PMD */
                VM_BUG_ON_PAGE(PageTransCompound(page), page);
@@ -1211,16 +1217,20 @@ void page_add_file_rmap(struct page *page, bool compound)
        VM_BUG_ON_PAGE(compound && !PageTransHuge(page), page);
        lock_page_memcg(page);
        if (compound && PageTransHuge(page)) {
-               for (i = 0, nr = 0; i < thp_nr_pages(page); i++) {
+               int nr_pages = thp_nr_pages(page);
+
+               for (i = 0, nr = 0; i < nr_pages; i++) {
                        if (atomic_inc_and_test(&page[i]._mapcount))
                                nr++;
                }
                if (!atomic_inc_and_test(compound_mapcount_ptr(page)))
                        goto out;
                if (PageSwapBacked(page))
-                       __inc_node_page_state(page, NR_SHMEM_PMDMAPPED);
+                       __mod_lruvec_page_state(page, NR_SHMEM_PMDMAPPED,
+                                               nr_pages);
                else
-                       __inc_node_page_state(page, NR_FILE_PMDMAPPED);
+                       __mod_lruvec_page_state(page, NR_FILE_PMDMAPPED,
+                                               nr_pages);
        } else {
                if (PageTransCompound(page) && page_mapping(page)) {
                        VM_WARN_ON_ONCE(!PageLocked(page));
@@ -1252,16 +1262,20 @@ static void page_remove_file_rmap(struct page *page, bool compound)
 
        /* page still mapped by someone else? */
        if (compound && PageTransHuge(page)) {
-               for (i = 0, nr = 0; i < thp_nr_pages(page); i++) {
+               int nr_pages = thp_nr_pages(page);
+
+               for (i = 0, nr = 0; i < nr_pages; i++) {
                        if (atomic_add_negative(-1, &page[i]._mapcount))
                                nr++;
                }
                if (!atomic_add_negative(-1, compound_mapcount_ptr(page)))
                        return;
                if (PageSwapBacked(page))
-                       __dec_node_page_state(page, NR_SHMEM_PMDMAPPED);
+                       __mod_lruvec_page_state(page, NR_SHMEM_PMDMAPPED,
+                                               -nr_pages);
                else
-                       __dec_node_page_state(page, NR_FILE_PMDMAPPED);
+                       __mod_lruvec_page_state(page, NR_FILE_PMDMAPPED,
+                                               -nr_pages);
        } else {
                if (!atomic_add_negative(-1, &page->_mapcount))
                        return;
@@ -1292,7 +1306,7 @@ static void page_remove_anon_compound_rmap(struct page *page)
        if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
                return;
 
-       __dec_lruvec_page_state(page, NR_ANON_THPS);
+       __mod_lruvec_page_state(page, NR_ANON_THPS, -thp_nr_pages(page));
 
        if (TestClearPageDoubleMap(page)) {
                /*
@@ -1722,9 +1736,9 @@ static bool invalid_migration_vma(struct vm_area_struct *vma, void *arg)
        return vma_is_temporary_stack(vma);
 }
 
-static int page_mapcount_is_zero(struct page *page)
+static int page_not_mapped(struct page *page)
 {
-       return !total_mapcount(page);
+       return !page_mapped(page);
 }
 
 /**
@@ -1742,7 +1756,7 @@ bool try_to_unmap(struct page *page, enum ttu_flags flags)
        struct rmap_walk_control rwc = {
                .rmap_one = try_to_unmap_one,
                .arg = (void *)flags,
-               .done = page_mapcount_is_zero,
+               .done = page_not_mapped,
                .anon_lock = page_lock_anon_vma_read,
        };
 
@@ -1766,11 +1780,6 @@ bool try_to_unmap(struct page *page, enum ttu_flags flags)
        return !page_mapcount(page) ? true : false;
 }
 
-static int page_not_mapped(struct page *page)
-{
-       return !page_mapped(page);
-};
-
 /**
  * try_to_munlock - try to munlock a page
  * @page: the page to be munlocked