-From ad7560171c6f2898fc8fa8e05730a978de531778 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
+From 9aa1345d66b8132745ffb99b348b1492088da9e2 Mon Sep 17 00:00:00 2001
+From: Hugh Dickins <hughd@google.com>
Date: Fri, 17 Nov 2023 00:49:18 -0800
Subject: mm: fix oops when filemap_map_pmd() without prealloc_pte
MIME-Version: 1.0
From: Hugh Dickins <hughd@google.com>
-[ Upstream commit 9aa1345d66b8132745ffb99b348b1492088da9e2 ]
+commit 9aa1345d66b8132745ffb99b348b1492088da9e2 upstream.
syzbot reports oops in lockdep's __lock_acquire(), called from
__pte_offset_map_lock() called from filemap_map_pages(); or when I run the
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: <stable@vger.kernel.org> [5.12+]
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Hugh Dickins <hughd@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
- mm/filemap.c | 2 +-
+ mm/filemap.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
-diff --git a/mm/filemap.c b/mm/filemap.c
-index 179eb8066c9b3..e653f2ad5aed1 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
-@@ -3209,7 +3209,7 @@ static bool filemap_map_pmd(struct vm_fault *vmf, struct page *page)
+@@ -3209,7 +3209,7 @@ static bool filemap_map_pmd(struct vm_fa
}
}
-- if (pmd_none(*vmf->pmd))
-+ if (pmd_none(*vmf->pmd) && vmf->prealloc_pte)
- pmd_install(mm, vmf->pmd, &vmf->prealloc_pte);
-
- /* See comment in handle_pte_fault() */
---
-2.42.0
-
+- if (pmd_none(*vmf->pmd)) {
++ if (pmd_none(*vmf->pmd) && vmf->prealloc_pte) {
+ vmf->ptl = pmd_lock(mm, vmf->pmd);
+ if (likely(pmd_none(*vmf->pmd))) {
+ mm_inc_nr_ptes(mm);
+++ /dev/null
-From ff6322441eedbfaa12d55c7d7024199b50945513 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri, 5 Nov 2021 13:38:38 -0700
-Subject: mm: introduce pmd_install() helper
-
-From: Qi Zheng <zhengqi.arch@bytedance.com>
-
-[ Upstream commit 03c4f20454e0231d2cdec4373841a3a25cf4efed ]
-
-Patch series "Do some code cleanups related to mm", v3.
-
-This patch (of 2):
-
-Currently we have three times the same few lines repeated in the code.
-Deduplicate them by newly introduced pmd_install() helper.
-
-Link: https://lkml.kernel.org/r/20210901102722.47686-1-zhengqi.arch@bytedance.com
-Link: https://lkml.kernel.org/r/20210901102722.47686-2-zhengqi.arch@bytedance.com
-Signed-off-by: Qi Zheng <zhengqi.arch@bytedance.com>
-Reviewed-by: David Hildenbrand <david@redhat.com>
-Reviewed-by: Muchun Song <songmuchun@bytedance.com>
-Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
-Cc: Thomas Gleixner <tglx@linutronix.de>
-Cc: Johannes Weiner <hannes@cmpxchg.org>
-Cc: Michal Hocko <mhocko@kernel.org>
-Cc: Vladimir Davydov <vdavydov.dev@gmail.com>
-Cc: Mika Penttila <mika.penttila@nextfour.com>
-Cc: Vlastimil Babka <vbabka@suse.cz>
-Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
-Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-Stable-dep-of: 9aa1345d66b8 ("mm: fix oops when filemap_map_pmd() without prealloc_pte")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- mm/filemap.c | 11 ++---------
- mm/internal.h | 1 +
- mm/memory.c | 34 ++++++++++++++++------------------
- 3 files changed, 19 insertions(+), 27 deletions(-)
-
-diff --git a/mm/filemap.c b/mm/filemap.c
-index 81e28722edfaf..179eb8066c9b3 100644
---- a/mm/filemap.c
-+++ b/mm/filemap.c
-@@ -3209,15 +3209,8 @@ static bool filemap_map_pmd(struct vm_fault *vmf, struct page *page)
- }
- }
-
-- if (pmd_none(*vmf->pmd)) {
-- vmf->ptl = pmd_lock(mm, vmf->pmd);
-- if (likely(pmd_none(*vmf->pmd))) {
-- mm_inc_nr_ptes(mm);
-- pmd_populate(mm, vmf->pmd, vmf->prealloc_pte);
-- vmf->prealloc_pte = NULL;
-- }
-- spin_unlock(vmf->ptl);
-- }
-+ if (pmd_none(*vmf->pmd))
-+ pmd_install(mm, vmf->pmd, &vmf->prealloc_pte);
-
- /* See comment in handle_pte_fault() */
- if (pmd_devmap_trans_unstable(vmf->pmd)) {
-diff --git a/mm/internal.h b/mm/internal.h
-index cf3cb933eba3f..6c3e1a9f8c5a6 100644
---- a/mm/internal.h
-+++ b/mm/internal.h
-@@ -38,6 +38,7 @@ vm_fault_t do_swap_page(struct vm_fault *vmf);
-
- void free_pgtables(struct mmu_gather *tlb, struct vm_area_struct *start_vma,
- unsigned long floor, unsigned long ceiling);
-+void pmd_install(struct mm_struct *mm, pmd_t *pmd, pgtable_t *pte);
-
- static inline bool can_madv_lru_vma(struct vm_area_struct *vma)
- {
-diff --git a/mm/memory.c b/mm/memory.c
-index 1bb01b12db532..46fcc91604814 100644
---- a/mm/memory.c
-+++ b/mm/memory.c
-@@ -433,9 +433,20 @@ void free_pgtables(struct mmu_gather *tlb, struct vm_area_struct *vma,
- }
- }
-
-+void pmd_install(struct mm_struct *mm, pmd_t *pmd, pgtable_t *pte)
-+{
-+ spinlock_t *ptl = pmd_lock(mm, pmd);
-+
-+ if (likely(pmd_none(*pmd))) { /* Has another populated it ? */
-+ mm_inc_nr_ptes(mm);
-+ pmd_populate(mm, pmd, *pte);
-+ *pte = NULL;
-+ }
-+ spin_unlock(ptl);
-+}
-+
- int __pte_alloc(struct mm_struct *mm, pmd_t *pmd)
- {
-- spinlock_t *ptl;
- pgtable_t new = pte_alloc_one(mm);
- if (!new)
- return -ENOMEM;
-@@ -455,13 +466,7 @@ int __pte_alloc(struct mm_struct *mm, pmd_t *pmd)
- */
- smp_wmb(); /* Could be smp_wmb__xxx(before|after)_spin_lock */
-
-- ptl = pmd_lock(mm, pmd);
-- if (likely(pmd_none(*pmd))) { /* Has another populated it ? */
-- mm_inc_nr_ptes(mm);
-- pmd_populate(mm, pmd, new);
-- new = NULL;
-- }
-- spin_unlock(ptl);
-+ pmd_install(mm, pmd, &new);
- if (new)
- pte_free(mm, new);
- return 0;
-@@ -4085,17 +4090,10 @@ vm_fault_t finish_fault(struct vm_fault *vmf)
- return ret;
- }
-
-- if (vmf->prealloc_pte) {
-- vmf->ptl = pmd_lock(vma->vm_mm, vmf->pmd);
-- if (likely(pmd_none(*vmf->pmd))) {
-- mm_inc_nr_ptes(vma->vm_mm);
-- pmd_populate(vma->vm_mm, vmf->pmd, vmf->prealloc_pte);
-- vmf->prealloc_pte = NULL;
-- }
-- spin_unlock(vmf->ptl);
-- } else if (unlikely(pte_alloc(vma->vm_mm, vmf->pmd))) {
-+ if (vmf->prealloc_pte)
-+ pmd_install(vma->vm_mm, vmf->pmd, &vmf->prealloc_pte);
-+ else if (unlikely(pte_alloc(vma->vm_mm, vmf->pmd)))
- return VM_FAULT_OOM;
-- }
- }
-
- /*
---
-2.42.0
-