]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - include/linux/mm.h
mm: make compound_head() robust
[mirror_ubuntu-bionic-kernel.git] / include / linux / mm.h
index 80001de019ba33d86b90b9922b39722270cb0449..9671b6f23edac81ced458674e715a267e4c434f6 100644 (file)
@@ -139,6 +139,7 @@ extern unsigned int kobjsize(const void *objp);
 
 #define VM_DONTCOPY    0x00020000      /* Do not copy this vma on fork */
 #define VM_DONTEXPAND  0x00040000      /* Cannot expand with mremap() */
+#define VM_LOCKONFAULT 0x00080000      /* Lock the pages covered when they are faulted in */
 #define VM_ACCOUNT     0x00100000      /* Is a VM accounted object */
 #define VM_NORESERVE   0x00200000      /* should the VM suppress accounting */
 #define VM_HUGETLB     0x00400000      /* Huge TLB Page VM */
@@ -202,6 +203,9 @@ extern unsigned int kobjsize(const void *objp);
 /* This mask defines which mm->def_flags a process can inherit its parent */
 #define VM_INIT_DEF_MASK       VM_NOHUGEPAGE
 
+/* This mask is used to clear all the VMA flags used by mlock */
+#define VM_LOCKED_CLEAR_MASK   (~(VM_LOCKED | VM_LOCKONFAULT))
+
 /*
  * mapping from the currently active vm_flags protection bits (the
  * low four bits) to a page protection mask..
@@ -426,46 +430,6 @@ static inline void compound_unlock_irqrestore(struct page *page,
 #endif
 }
 
-static inline struct page *compound_head_by_tail(struct page *tail)
-{
-       struct page *head = tail->first_page;
-
-       /*
-        * page->first_page may be a dangling pointer to an old
-        * compound page, so recheck that it is still a tail
-        * page before returning.
-        */
-       smp_rmb();
-       if (likely(PageTail(tail)))
-               return head;
-       return tail;
-}
-
-/*
- * Since either compound page could be dismantled asynchronously in THP
- * or we access asynchronously arbitrary positioned struct page, there
- * would be tail flag race. To handle this race, we should call
- * smp_rmb() before checking tail flag. compound_head_by_tail() did it.
- */
-static inline struct page *compound_head(struct page *page)
-{
-       if (unlikely(PageTail(page)))
-               return compound_head_by_tail(page);
-       return page;
-}
-
-/*
- * If we access compound page synchronously such as access to
- * allocated page, there is no need to handle tail flag race, so we can
- * check tail flag directly without any synchronization primitive.
- */
-static inline struct page *compound_head_fast(struct page *page)
-{
-       if (unlikely(PageTail(page)))
-               return page->first_page;
-       return page;
-}
-
 /*
  * The atomic page->_mapcount, starts from -1: so that transitions
  * both from it and to it can be tracked, using atomic_inc_and_test
@@ -514,7 +478,7 @@ static inline void get_huge_page_tail(struct page *page)
        VM_BUG_ON_PAGE(!PageTail(page), page);
        VM_BUG_ON_PAGE(page_mapcount(page) < 0, page);
        VM_BUG_ON_PAGE(atomic_read(&page->_count) != 0, page);
-       if (compound_tail_refcounted(page->first_page))
+       if (compound_tail_refcounted(compound_head(page)))
                atomic_inc(&page->_mapcount);
 }
 
@@ -537,13 +501,7 @@ static inline struct page *virt_to_head_page(const void *x)
 {
        struct page *page = virt_to_page(x);
 
-       /*
-        * We don't need to worry about synchronization of tail flag
-        * when we call virt_to_head_page() since it is only called for
-        * already allocated page and this page won't be freed until
-        * this virt_to_head_page() is finished. So use _fast variant.
-        */
-       return compound_head_fast(page);
+       return compound_head(page);
 }
 
 /*
@@ -564,18 +522,32 @@ int split_free_page(struct page *page);
 /*
  * Compound pages have a destructor function.  Provide a
  * prototype for that function and accessor functions.
- * These are _only_ valid on the head of a PG_compound page.
+ * These are _only_ valid on the head of a compound page.
  */
+typedef void compound_page_dtor(struct page *);
+
+/* Keep the enum in sync with compound_page_dtors array in mm/page_alloc.c */
+enum compound_dtor_id {
+       NULL_COMPOUND_DTOR,
+       COMPOUND_PAGE_DTOR,
+#ifdef CONFIG_HUGETLB_PAGE
+       HUGETLB_PAGE_DTOR,
+#endif
+       NR_COMPOUND_DTORS,
+};
+extern compound_page_dtor * const compound_page_dtors[];
 
 static inline void set_compound_page_dtor(struct page *page,
-                                               compound_page_dtor *dtor)
+               enum compound_dtor_id compound_dtor)
 {
-       page[1].compound_dtor = dtor;
+       VM_BUG_ON_PAGE(compound_dtor >= NR_COMPOUND_DTORS, page);
+       page[1].compound_dtor = compound_dtor;
 }
 
 static inline compound_page_dtor *get_compound_page_dtor(struct page *page)
 {
-       return page[1].compound_dtor;
+       VM_BUG_ON_PAGE(page[1].compound_dtor >= NR_COMPOUND_DTORS, page);
+       return compound_page_dtors[page[1].compound_dtor];
 }
 
 static inline int compound_order(struct page *page)
@@ -585,7 +557,7 @@ static inline int compound_order(struct page *page)
        return page[1].compound_order;
 }
 
-static inline void set_compound_order(struct page *page, unsigned long order)
+static inline void set_compound_order(struct page *page, unsigned int order)
 {
        page[1].compound_order = order;
 }
@@ -1568,8 +1540,7 @@ static inline bool ptlock_init(struct page *page)
         * with 0. Make sure nobody took it in use in between.
         *
         * It can happen if arch try to use slab for page table allocation:
-        * slab code uses page->slab_cache and page->first_page (for tail
-        * pages), which share storage with page->ptl.
+        * slab code uses page->slab_cache, which share storage with page->ptl.
         */
        VM_BUG_ON_PAGE(*(unsigned long *)&page->ptl, page);
        if (!ptlock_alloc(page))
@@ -1606,8 +1577,10 @@ static inline void pgtable_init(void)
 
 static inline bool pgtable_page_ctor(struct page *page)
 {
+       if (!ptlock_init(page))
+               return false;
        inc_zone_page_state(page, NR_PAGETABLE);
-       return ptlock_init(page);
+       return true;
 }
 
 static inline void pgtable_page_dtor(struct page *page)
@@ -2036,8 +2009,6 @@ void page_cache_async_readahead(struct address_space *mapping,
                                pgoff_t offset,
                                unsigned long size);
 
-unsigned long max_sane_readahead(unsigned long nr);
-
 /* Generic expand stack which grows the stack according to GROWS{UP,DOWN} */
 extern int expand_stack(struct vm_area_struct *vma, unsigned long address);
 
@@ -2137,6 +2108,7 @@ static inline struct page *follow_page(struct vm_area_struct *vma,
 #define FOLL_NUMA      0x200   /* force NUMA hinting page fault */
 #define FOLL_MIGRATION 0x400   /* wait for page to replace migration entry */
 #define FOLL_TRIED     0x800   /* a retry, previous pass started an IO */
+#define FOLL_MLOCK     0x1000  /* lock present pages */
 
 typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr,
                        void *data);