Hi: On 2021/6/14 10:12, Naoya Horiguchi wrote: > From: Naoya Horiguchi <naoya.horiguchi@xxxxxxx> > > Originally mf_mutex is introduced to serialize multiple MCE events, but > it's also helpful to exclude races among soft_offline_page() and > unpoison_memory(). So apply mf_mutex to them. > When I was investigating the memory-failure code, I realized these possible races too. It's very kind of you to fix these races! Many thanks! > Signed-off-by: Naoya Horiguchi <naoya.horiguchi@xxxxxxx> > --- > mm/memory-failure.c | 26 ++++++++++++++++++-------- > 1 file changed, 18 insertions(+), 8 deletions(-) > > diff --git v5.13-rc5/mm/memory-failure.c v5.13-rc5_patched/mm/memory-failure.c > index ae30fd6d575a..280eb6d6dd15 100644 > --- v5.13-rc5/mm/memory-failure.c > +++ v5.13-rc5_patched/mm/memory-failure.c > @@ -1583,6 +1583,8 @@ static int memory_failure_dev_pagemap(unsigned long pfn, int flags, > return rc; > } > > +static DEFINE_MUTEX(mf_mutex); > + > /** > * memory_failure - Handle memory failure of a page. > * @pfn: Page Number of the corrupted page > @@ -1609,7 +1611,6 @@ int memory_failure(unsigned long pfn, int flags) > int res = 0; > unsigned long page_flags; > bool retry = true; > - static DEFINE_MUTEX(mf_mutex); > > if (!sysctl_memory_failure_recovery) > panic("Memory failure on page %lx", pfn); > @@ -1918,6 +1919,7 @@ int unpoison_memory(unsigned long pfn) > struct page *page; > struct page *p; > int freeit = 0; > + int ret = 0; > unsigned long flags = 0; > static DEFINE_RATELIMIT_STATE(unpoison_rs, DEFAULT_RATELIMIT_INTERVAL, > DEFAULT_RATELIMIT_BURST); > @@ -1928,28 +1930,30 @@ int unpoison_memory(unsigned long pfn) > p = pfn_to_page(pfn); > page = compound_head(p); > > + mutex_lock(&mf_mutex); > + > if (!PageHWPoison(p)) { > unpoison_pr_info("Unpoison: Page was already unpoisoned %#lx\n", > pfn, &unpoison_rs); > - return 0; > + goto unlock_mutex; > } > > if (page_count(page) > 1) { > unpoison_pr_info("Unpoison: Someone grabs the hwpoison page %#lx\n", > pfn, &unpoison_rs); > - return 0; > + goto unlock_mutex; > } > > if (page_mapped(page)) { > unpoison_pr_info("Unpoison: Someone maps the hwpoison page %#lx\n", > pfn, &unpoison_rs); > - return 0; > + goto unlock_mutex; > } > > if (page_mapping(page)) { > unpoison_pr_info("Unpoison: the hwpoison page has non-NULL mapping %#lx\n", > pfn, &unpoison_rs); > - return 0; > + goto unlock_mutex; > } > > /* > @@ -1960,7 +1964,7 @@ int unpoison_memory(unsigned long pfn) > if (!PageHuge(page) && PageTransHuge(page)) { > unpoison_pr_info("Unpoison: Memory failure is now running on %#lx\n", > pfn, &unpoison_rs); > - return 0; > + goto unlock_mutex; > } > Maybe it's more appropriate to start mutex_lock(&mf_mutex) here? I think these races start here. > if (!get_hwpoison_page(p, flags)) { > @@ -1968,7 +1972,7 @@ int unpoison_memory(unsigned long pfn) > num_poisoned_pages_dec(); > unpoison_pr_info("Unpoison: Software-unpoisoned free page %#lx\n", > pfn, &unpoison_rs); > - return 0; > + goto unlock_mutex; > } > > lock_page(page); > @@ -1990,7 +1994,9 @@ int unpoison_memory(unsigned long pfn) > if (freeit && !(pfn == my_zero_pfn(0) && page_count(p) == 1)) > put_page(page); > > - return 0; > +unlock_mutex: > + mutex_unlock(&mf_mutex); > + return ret; > } > EXPORT_SYMBOL(unpoison_memory); > > @@ -2171,6 +2177,8 @@ int soft_offline_page(unsigned long pfn, int flags) > return -EIO; > } > > + mutex_lock(&mf_mutex); > + > if (PageHWPoison(page)) { > pr_info("%s: %#lx page already poisoned\n", __func__, pfn); > put_ref_page(ref_page); > @@ -2194,5 +2202,7 @@ int soft_offline_page(unsigned long pfn, int flags) > __func__, pfn, page->flags, &page->flags); > } > > + mutex_unlock(&mf_mutex); > + > return ret; > } >