| From: Hugh Dickins <hughd@google.com> |
| Subject: mm/thp: fix deferred split queue not partially_mapped: fix |
| Date: Sun, 10 Nov 2024 13:11:21 -0800 (PST) |
| |
| Though even more elusive than before, list_del corruption has still been |
| seen on THP's deferred split queue. |
| |
| The idea in commit e66f3185fa04 was right, but its implementation wrong. |
| The context omitted an important comment just before the critical test: |
| "split_folio() removes folio from list on success." In ignoring that |
| comment, when a THP split succeeded, the code went on to release the |
| preceding safe folio, preserving instead an irrelevant (formerly head) |
| folio: which gives no safety because it's not on the list. Fix the logic. |
| |
| Link: https://lkml.kernel.org/r/3c995a30-31ce-0998-1b9f-3a2cb9354c91@google.com |
| Fixes: e66f3185fa04 ("mm/thp: fix deferred split queue not partially_mapped") |
| Signed-off-by: Hugh Dickins <hughd@google.com> |
| Acked-by: Usama Arif <usamaarif642@gmail.com> |
| Reviewed-by: Zi Yan <ziy@nvidia.com> |
| Cc: Baolin Wang <baolin.wang@linux.alibaba.com> |
| Cc: Barry Song <baohua@kernel.org> |
| Cc: Chris Li <chrisl@kernel.org> |
| Cc: David Hildenbrand <david@redhat.com> |
| Cc: Johannes Weiner <hannes@cmpxchg.org> |
| Cc: Kefeng Wang <wangkefeng.wang@huawei.com> |
| Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> |
| Cc: Matthew Wilcox <willy@infradead.org> |
| Cc: Nhat Pham <nphamcs@gmail.com> |
| Cc: Ryan Roberts <ryan.roberts@arm.com> |
| Cc: Shakeel Butt <shakeel.butt@linux.dev> |
| Cc: Wei Yang <richard.weiyang@gmail.com> |
| Cc: Yang Shi <shy828301@gmail.com> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| --- |
| |
| mm/huge_memory.c | 4 +++- |
| 1 file changed, 3 insertions(+), 1 deletion(-) |
| |
| --- a/mm/huge_memory.c~mm-thp-fix-deferred-split-queue-not-partially_mapped-fix |
| +++ a/mm/huge_memory.c |
| @@ -3790,7 +3790,9 @@ next: |
| * in the case it was underused, then consider it used and |
| * don't add it back to split_queue. |
| */ |
| - if (!did_split && !folio_test_partially_mapped(folio)) { |
| + if (did_split) { |
| + ; /* folio already removed from list */ |
| + } else if (!folio_test_partially_mapped(folio)) { |
| list_del_init(&folio->_deferred_list); |
| removed++; |
| } else { |
| _ |