From: Sasha Levin Date: Thu, 1 Jul 2021 11:27:21 +0000 (-0400) Subject: Fixes for 4.9 X-Git-Tag: v5.13.1~17 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=560a45ec15ad78dbc619b5235eb13012c942ee3f;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 4.9 Signed-off-by: Sasha Levin --- diff --git a/queue-4.9/include-linux-mmdebug.h-make-vm_warn-non-rvals.patch b/queue-4.9/include-linux-mmdebug.h-make-vm_warn-non-rvals.patch new file mode 100644 index 00000000000..f2a1276c85b --- /dev/null +++ b/queue-4.9/include-linux-mmdebug.h-make-vm_warn-non-rvals.patch @@ -0,0 +1,55 @@ +From eb5785dc9c1e96290a6d31a3bd35a3346adf89ca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Apr 2018 16:25:30 -0700 +Subject: include/linux/mmdebug.h: make VM_WARN* non-rvals + +From: Michal Hocko + +[ Upstream commit 91241681c62a5a690c88eb2aca027f094125eaac ] + +At present the construct + + if (VM_WARN(...)) + +will compile OK with CONFIG_DEBUG_VM=y and will fail with +CONFIG_DEBUG_VM=n. The reason is that VM_{WARN,BUG}* have always been +special wrt. {WARN/BUG}* and never generate any code when DEBUG_VM is +disabled. So we cannot really use it in conditionals. + +We considered changing things so that this construct works in both cases +but that might cause unwanted code generation with CONFIG_DEBUG_VM=n. +It is safer and simpler to make the build fail in both cases. + +[akpm@linux-foundation.org: changelog] +Signed-off-by: Michal Hocko +Reviewed-by: Andrew Morton +Cc: Stephen Rothwell +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Sasha Levin +--- + include/linux/mmdebug.h | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h +index 451a811f48f2..deaba1cc3cfc 100644 +--- a/include/linux/mmdebug.h ++++ b/include/linux/mmdebug.h +@@ -36,10 +36,10 @@ void dump_mm(const struct mm_struct *mm); + BUG(); \ + } \ + } while (0) +-#define VM_WARN_ON(cond) WARN_ON(cond) +-#define VM_WARN_ON_ONCE(cond) WARN_ON_ONCE(cond) +-#define VM_WARN_ONCE(cond, format...) WARN_ONCE(cond, format) +-#define VM_WARN(cond, format...) WARN(cond, format) ++#define VM_WARN_ON(cond) (void)WARN_ON(cond) ++#define VM_WARN_ON_ONCE(cond) (void)WARN_ON_ONCE(cond) ++#define VM_WARN_ONCE(cond, format...) (void)WARN_ONCE(cond, format) ++#define VM_WARN(cond, format...) (void)WARN(cond, format) + #else + #define VM_BUG_ON(cond) BUILD_BUG_ON_INVALID(cond) + #define VM_BUG_ON_PAGE(cond, page) VM_BUG_ON(cond) +-- +2.30.2 + diff --git a/queue-4.9/mm-add-vm_warn_on_once_page-macro.patch b/queue-4.9/mm-add-vm_warn_on_once_page-macro.patch new file mode 100644 index 00000000000..9b4a0506a43 --- /dev/null +++ b/queue-4.9/mm-add-vm_warn_on_once_page-macro.patch @@ -0,0 +1,64 @@ +From 11bf0a3308317e24a18002a8a215faad89b8406e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 18 Dec 2020 14:01:31 -0800 +Subject: mm: add VM_WARN_ON_ONCE_PAGE() macro + +From: Alex Shi + +[ Upstream commit a4055888629bc0467d12d912cd7c90acdf3d9b12 part ] + +Add VM_WARN_ON_ONCE_PAGE() macro. + +Link: https://lkml.kernel.org/r/1604283436-18880-3-git-send-email-alex.shi@linux.alibaba.com +Signed-off-by: Alex Shi +Acked-by: Michal Hocko +Acked-by: Hugh Dickins +Acked-by: Johannes Weiner +Cc: Vladimir Davydov +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds + +Note on stable backport: original commit was titled +mm/memcg: warning on !memcg after readahead page charged +which included uses of this macro in mm/memcontrol.c: here omitted. + +Signed-off-by: Hugh Dickins +Signed-off-by: Sasha Levin +--- + include/linux/mmdebug.h | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h +index deaba1cc3cfc..d1fb3bbff37a 100644 +--- a/include/linux/mmdebug.h ++++ b/include/linux/mmdebug.h +@@ -36,6 +36,18 @@ void dump_mm(const struct mm_struct *mm); + BUG(); \ + } \ + } while (0) ++#define VM_WARN_ON_ONCE_PAGE(cond, page) ({ \ ++ static bool __section(".data.once") __warned; \ ++ int __ret_warn_once = !!(cond); \ ++ \ ++ if (unlikely(__ret_warn_once && !__warned)) { \ ++ dump_page(page, "VM_WARN_ON_ONCE_PAGE(" __stringify(cond)")");\ ++ __warned = true; \ ++ WARN_ON(1); \ ++ } \ ++ unlikely(__ret_warn_once); \ ++}) ++ + #define VM_WARN_ON(cond) (void)WARN_ON(cond) + #define VM_WARN_ON_ONCE(cond) (void)WARN_ON_ONCE(cond) + #define VM_WARN_ONCE(cond, format...) (void)WARN_ONCE(cond, format) +@@ -47,6 +59,7 @@ void dump_mm(const struct mm_struct *mm); + #define VM_BUG_ON_MM(cond, mm) VM_BUG_ON(cond) + #define VM_WARN_ON(cond) BUILD_BUG_ON_INVALID(cond) + #define VM_WARN_ON_ONCE(cond) BUILD_BUG_ON_INVALID(cond) ++#define VM_WARN_ON_ONCE_PAGE(cond, page) BUILD_BUG_ON_INVALID(cond) + #define VM_WARN_ONCE(cond, format...) BUILD_BUG_ON_INVALID(cond) + #define VM_WARN(cond, format...) BUILD_BUG_ON_INVALID(cond) + #endif +-- +2.30.2 + diff --git a/queue-4.9/mm-futex-fix-shared-futex-pgoff-on-shmem-huge-page.patch b/queue-4.9/mm-futex-fix-shared-futex-pgoff-on-shmem-huge-page.patch new file mode 100644 index 00000000000..f7b5d891fc1 --- /dev/null +++ b/queue-4.9/mm-futex-fix-shared-futex-pgoff-on-shmem-huge-page.patch @@ -0,0 +1,165 @@ +From a7d5a2d099cd1070d021ef21f32da3c5556868a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 24 Jun 2021 18:39:52 -0700 +Subject: mm, futex: fix shared futex pgoff on shmem huge page + +From: Hugh Dickins + +[ Upstream commit fe19bd3dae3d15d2fbfdb3de8839a6ea0fe94264 ] + +If more than one futex is placed on a shmem huge page, it can happen +that waking the second wakes the first instead, and leaves the second +waiting: the key's shared.pgoff is wrong. + +When 3.11 commit 13d60f4b6ab5 ("futex: Take hugepages into account when +generating futex_key"), the only shared huge pages came from hugetlbfs, +and the code added to deal with its exceptional page->index was put into +hugetlb source. Then that was missed when 4.8 added shmem huge pages. + +page_to_pgoff() is what others use for this nowadays: except that, as +currently written, it gives the right answer on hugetlbfs head, but +nonsense on hugetlbfs tails. Fix that by calling hugetlbfs-specific +hugetlb_basepage_index() on PageHuge tails as well as on head. + +Yes, it's unconventional to declare hugetlb_basepage_index() there in +pagemap.h, rather than in hugetlb.h; but I do not expect anything but +page_to_pgoff() ever to need it. + +[akpm@linux-foundation.org: give hugetlb_basepage_index() prototype the correct scope] + +Link: https://lkml.kernel.org/r/b17d946b-d09-326e-b42a-52884c36df32@google.com +Fixes: 800d8c63b2e9 ("shmem: add huge pages support") +Reported-by: Neel Natu +Signed-off-by: Hugh Dickins +Reviewed-by: Matthew Wilcox (Oracle) +Acked-by: Thomas Gleixner +Cc: "Kirill A. Shutemov" +Cc: Zhang Yi +Cc: Mel Gorman +Cc: Mike Kravetz +Cc: Ingo Molnar +Cc: Peter Zijlstra +Cc: Darren Hart +Cc: Davidlohr Bueso +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds + +Note on stable backport: leave redundant #include +in kernel/futex.c, to avoid conflict over the header files included. +Resolved trivial conflicts in include/linux/hugetlb.h. + +Signed-off-by: Hugh Dickins +Signed-off-by: Sasha Levin +--- + include/linux/hugetlb.h | 15 --------------- + include/linux/pagemap.h | 13 +++++++------ + kernel/futex.c | 2 +- + mm/hugetlb.c | 5 +---- + 4 files changed, 9 insertions(+), 26 deletions(-) + +diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h +index 8dd365c65478..6417bc845db5 100644 +--- a/include/linux/hugetlb.h ++++ b/include/linux/hugetlb.h +@@ -451,17 +451,6 @@ static inline int hstate_index(struct hstate *h) + return h - hstates; + } + +-pgoff_t __basepage_index(struct page *page); +- +-/* Return page->index in PAGE_SIZE units */ +-static inline pgoff_t basepage_index(struct page *page) +-{ +- if (!PageCompound(page)) +- return page->index; +- +- return __basepage_index(page); +-} +- + extern int dissolve_free_huge_pages(unsigned long start_pfn, + unsigned long end_pfn); + static inline bool hugepage_migration_supported(struct hstate *h) +@@ -529,10 +518,6 @@ static inline unsigned int pages_per_huge_page(struct hstate *h) + #define hstate_index_to_shift(index) 0 + #define hstate_index(h) 0 + +-static inline pgoff_t basepage_index(struct page *page) +-{ +- return page->index; +-} + #define dissolve_free_huge_pages(s, e) 0 + #define hugepage_migration_supported(h) false + +diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h +index 35f4c4d9c405..8672291633dd 100644 +--- a/include/linux/pagemap.h ++++ b/include/linux/pagemap.h +@@ -374,7 +374,7 @@ static inline struct page *read_mapping_page(struct address_space *mapping, + } + + /* +- * Get index of the page with in radix-tree ++ * Get index of the page within radix-tree (but not for hugetlb pages). + * (TODO: remove once hugetlb pages will have ->index in PAGE_SIZE) + */ + static inline pgoff_t page_to_index(struct page *page) +@@ -393,15 +393,16 @@ static inline pgoff_t page_to_index(struct page *page) + return pgoff; + } + ++extern pgoff_t hugetlb_basepage_index(struct page *page); ++ + /* +- * Get the offset in PAGE_SIZE. +- * (TODO: hugepage should have ->index in PAGE_SIZE) ++ * Get the offset in PAGE_SIZE (even for hugetlb pages). ++ * (TODO: hugetlb pages should have ->index in PAGE_SIZE) + */ + static inline pgoff_t page_to_pgoff(struct page *page) + { +- if (unlikely(PageHeadHuge(page))) +- return page->index << compound_order(page); +- ++ if (unlikely(PageHuge(page))) ++ return hugetlb_basepage_index(page); + return page_to_index(page); + } + +diff --git a/kernel/futex.c b/kernel/futex.c +index 324fb85c8904..b3823736af6f 100644 +--- a/kernel/futex.c ++++ b/kernel/futex.c +@@ -717,7 +717,7 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) + + key->both.offset |= FUT_OFF_INODE; /* inode-based key */ + key->shared.i_seq = get_inode_sequence_number(inode); +- key->shared.pgoff = basepage_index(tail); ++ key->shared.pgoff = page_to_pgoff(tail); + rcu_read_unlock(); + } + +diff --git a/mm/hugetlb.c b/mm/hugetlb.c +index b7215b0807ca..de89e9295f6c 100644 +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -1380,15 +1380,12 @@ int PageHeadHuge(struct page *page_head) + return get_compound_page_dtor(page_head) == free_huge_page; + } + +-pgoff_t __basepage_index(struct page *page) ++pgoff_t hugetlb_basepage_index(struct page *page) + { + struct page *page_head = compound_head(page); + pgoff_t index = page_index(page_head); + unsigned long compound_idx; + +- if (!PageHuge(page_head)) +- return page_index(page); +- + if (compound_order(page_head) >= MAX_ORDER) + compound_idx = page_to_pfn(page) - page_to_pfn(page_head); + else +-- +2.30.2 + diff --git a/queue-4.9/mm-thp-replace-debug_vm-bug-with-vm_warn-when-unmap-.patch b/queue-4.9/mm-thp-replace-debug_vm-bug-with-vm_warn-when-unmap-.patch new file mode 100644 index 00000000000..77c43867b11 --- /dev/null +++ b/queue-4.9/mm-thp-replace-debug_vm-bug-with-vm_warn-when-unmap-.patch @@ -0,0 +1,134 @@ +From a701cffdd3e2ed7f63e3fb553f78511519888299 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 15 Jun 2021 18:24:07 -0700 +Subject: mm: thp: replace DEBUG_VM BUG with VM_WARN when unmap fails for split + +From: Yang Shi + +[ Upstream commit 504e070dc08f757bccaed6d05c0f53ecbfac8a23 ] + +When debugging the bug reported by Wang Yugui [1], try_to_unmap() may +fail, but the first VM_BUG_ON_PAGE() just checks page_mapcount() however +it may miss the failure when head page is unmapped but other subpage is +mapped. Then the second DEBUG_VM BUG() that check total mapcount would +catch it. This may incur some confusion. + +As this is not a fatal issue, so consolidate the two DEBUG_VM checks +into one VM_WARN_ON_ONCE_PAGE(). + +[1] https://lore.kernel.org/linux-mm/20210412180659.B9E3.409509F4@e16-tech.com/ + +Link: https://lkml.kernel.org/r/d0f0db68-98b8-ebfb-16dc-f29df24cf012@google.com +Signed-off-by: Yang Shi +Reviewed-by: Zi Yan +Acked-by: Kirill A. Shutemov +Signed-off-by: Hugh Dickins +Cc: Alistair Popple +Cc: Jan Kara +Cc: Jue Wang +Cc: "Matthew Wilcox (Oracle)" +Cc: Miaohe Lin +Cc: Minchan Kim +Cc: Naoya Horiguchi +Cc: Oscar Salvador +Cc: Peter Xu +Cc: Ralph Campbell +Cc: Shakeel Butt +Cc: Wang Yugui +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds + +Note on stable backport: fixed up variables, split_queue_lock, tree_lock +in split_huge_page_to_list(); adapted to early version of unmap_page(). + +Signed-off-by: Hugh Dickins +Signed-off-by: Sasha Levin +--- + mm/huge_memory.c | 29 ++++++++++------------------- + 1 file changed, 10 insertions(+), 19 deletions(-) + +diff --git a/mm/huge_memory.c b/mm/huge_memory.c +index 14cd0ef33b62..177ca028b986 100644 +--- a/mm/huge_memory.c ++++ b/mm/huge_memory.c +@@ -1891,7 +1891,7 @@ static void unmap_page(struct page *page) + { + enum ttu_flags ttu_flags = TTU_IGNORE_MLOCK | TTU_IGNORE_ACCESS | + TTU_RMAP_LOCKED; +- int i, ret; ++ int i; + + VM_BUG_ON_PAGE(!PageHead(page), page); + +@@ -1899,15 +1899,16 @@ static void unmap_page(struct page *page) + ttu_flags |= TTU_MIGRATION; + + /* We only need TTU_SPLIT_HUGE_PMD once */ +- ret = try_to_unmap(page, ttu_flags | TTU_SPLIT_HUGE_PMD); +- for (i = 1; !ret && i < HPAGE_PMD_NR; i++) { ++ try_to_unmap(page, ttu_flags | TTU_SPLIT_HUGE_PMD); ++ for (i = 1; i < HPAGE_PMD_NR; i++) { + /* Cut short if the page is unmapped */ + if (page_count(page) == 1) + return; + +- ret = try_to_unmap(page + i, ttu_flags); ++ try_to_unmap(page + i, ttu_flags); + } +- VM_BUG_ON_PAGE(ret, page + i - 1); ++ ++ VM_WARN_ON_ONCE_PAGE(page_mapped(page), page); + } + + static void remap_page(struct page *page) +@@ -2137,7 +2138,7 @@ int split_huge_page_to_list(struct page *page, struct list_head *list) + struct pglist_data *pgdata = NODE_DATA(page_to_nid(head)); + struct anon_vma *anon_vma = NULL; + struct address_space *mapping = NULL; +- int count, mapcount, extra_pins, ret; ++ int extra_pins, ret; + bool mlocked; + unsigned long flags; + pgoff_t end; +@@ -2200,7 +2201,6 @@ int split_huge_page_to_list(struct page *page, struct list_head *list) + + mlocked = PageMlocked(page); + unmap_page(head); +- VM_BUG_ON_PAGE(compound_mapcount(head), head); + + /* Make sure the page is not on per-CPU pagevec as it takes pin */ + if (mlocked) +@@ -2226,9 +2226,7 @@ int split_huge_page_to_list(struct page *page, struct list_head *list) + + /* Prevent deferred_split_scan() touching ->_refcount */ + spin_lock(&pgdata->split_queue_lock); +- count = page_count(head); +- mapcount = total_mapcount(head); +- if (!mapcount && page_ref_freeze(head, 1 + extra_pins)) { ++ if (page_ref_freeze(head, 1 + extra_pins)) { + if (!list_empty(page_deferred_list(head))) { + pgdata->split_queue_len--; + list_del(page_deferred_list(head)); +@@ -2239,16 +2237,9 @@ int split_huge_page_to_list(struct page *page, struct list_head *list) + __split_huge_page(page, list, end, flags); + ret = 0; + } else { +- if (IS_ENABLED(CONFIG_DEBUG_VM) && mapcount) { +- pr_alert("total_mapcount: %u, page_count(): %u\n", +- mapcount, count); +- if (PageTail(page)) +- dump_page(head, NULL); +- dump_page(page, "total_mapcount(head) > 0"); +- BUG(); +- } + spin_unlock(&pgdata->split_queue_lock); +-fail: if (mapping) ++fail: ++ if (mapping) + spin_unlock(&mapping->tree_lock); + spin_unlock_irqrestore(zone_lru_lock(page_zone(head)), flags); + remap_page(head); +-- +2.30.2 + diff --git a/queue-4.9/series b/queue-4.9/series new file mode 100644 index 00000000000..c64bce199cf --- /dev/null +++ b/queue-4.9/series @@ -0,0 +1,4 @@ +include-linux-mmdebug.h-make-vm_warn-non-rvals.patch +mm-add-vm_warn_on_once_page-macro.patch +mm-thp-replace-debug_vm-bug-with-vm_warn-when-unmap-.patch +mm-futex-fix-shared-futex-pgoff-on-shmem-huge-page.patch