From 60c5a0e02390868b67f3ddfe63285a132de5db5d Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Tue, 2 Jan 2024 15:32:56 -0800 Subject: [PATCH] UPSTREAM: userfaultfd: fix move_pages_pte() splitting folio under RCU read lock While testing the split PMD path with lockdep enabled I've got an "Invalid wait context" error caused by split_huge_page_to_list() trying to lock anon_vma->rwsem while inside RCU read section. The issues is due to move_pages_pte() calling split_folio() under RCU read lock. Fix this by unmapping the PTEs and exiting RCU read section before splitting the folio and then retrying. The same retry pattern is used when locking the folio or anon_vma in this function. After splitting the large folio we unlock and release it because after the split the old folio might not be the one that contains the src_addr. Link: https://lkml.kernel.org/r/20240102233256.1077959-1-surenb@google.com Fixes: adef440691ba ("userfaultfd: UFFDIO_MOVE uABI") Signed-off-by: Suren Baghdasaryan Reviewed-by: Peter Xu Cc: Al Viro Cc: Andrea Arcangeli Cc: Axel Rasmussen Cc: Brian Geffon Cc: Christian Brauner Cc: David Hildenbrand Cc: Hugh Dickins Cc: Jann Horn Cc: Kalesh Singh Cc: Liam R. Howlett Cc: Lokesh Gidra Cc: Matthew Wilcox (Oracle) Cc: Michal Hocko Cc: Mike Rapoport (IBM) Cc: Nicolas Geoffray Cc: Peter Xu Cc: Ryan Roberts Cc: Shuah Khan Cc: ZhangPeng Signed-off-by: Andrew Morton (cherry picked from commit 982ae058b2f08f576e4f3d4055f8916ba789f3d4) Bug: 274911254 Change-Id: I382c6631d821b0ed26d9b15afa78a417dafaeb2e Signed-off-by: Suren Baghdasaryan Signed-off-by: Lokesh Gidra --- mm/userfaultfd.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c index 9063874993d3..bb19455d36e2 100644 --- a/mm/userfaultfd.c +++ b/mm/userfaultfd.c @@ -1030,9 +1030,18 @@ retry: /* at this point we have src_folio locked */ if (folio_test_large(src_folio)) { + /* split_folio() can block */ + pte_unmap(&orig_src_pte); + pte_unmap(&orig_dst_pte); + src_pte = dst_pte = NULL; err = split_folio(src_folio); if (err) goto out; + /* have to reacquire the folio after it got split */ + folio_unlock(src_folio); + folio_put(src_folio); + src_folio = NULL; + goto retry; } if (!src_anon_vma) {