Message ID | 20220712032858.170414-5-naoya.horiguchi@linux.dev (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | mm, hwpoison: enable 1GB hugepage support (v6) | expand |
On 2022/7/12 11:28, Naoya Horiguchi wrote: > From: Naoya Horiguchi <naoya.horiguchi@nec.com> > > Raw error info list needs to be removed when hwpoisoned hugetlb is > unpoisoned. And unpoison handler needs to know how many errors there > are in the target hugepage. So add them. > > HPageVmemmapOptimized(hpage) and HPageRawHwpUnreliable(hpage)) can't be > unpoisoned, so let's skip them. > > Signed-off-by: Naoya Horiguchi <naoya.horiguchi@nec.com> > Reported-by: kernel test robot <lkp@intel.com> This patch looks good to me with some nits below. > --- ... > > -void hugetlb_clear_page_hwpoison(struct page *hpage) > +static unsigned long free_raw_hwp_pages(struct page *hpage, bool move_flag) > { > struct llist_head *head; > struct llist_node *t, *tnode; > + unsigned long count = 0; > > - if (!HPageRawHwpUnreliable(hpage)) > - ClearPageHWPoison(hpage); > + /* > + * HPageVmemmapOptimized hugepages can't be unpoisoned because > + * struct pages for tail pages are required to free hwpoisoned > + * hugepages. HPageRawHwpUnreliable hugepages shouldn't be > + * unpoisoned by definition. > + */ > + if (HPageVmemmapOptimized(hpage) || HPageRawHwpUnreliable(hpage)) If move_flag == false, i.e. in unpoison case, tail pages are not touched. So HPageVmemmapOptimized can be ignored in this case? Or leave it as above to keep the code simple? > + return 0; > head = raw_hwp_list_head(hpage); > llist_for_each_safe(tnode, t, head->first) { > struct raw_hwp_page *p = container_of(tnode, struct raw_hwp_page, node); > > - SetPageHWPoison(p->page); > + if (move_flag) > + SetPageHWPoison(p->page); > kfree(p); > + count++; > } > llist_del_all(head); > + return count; > +} > + > +void hugetlb_clear_page_hwpoison(struct page *hpage) > +{ > + if (!HPageRawHwpUnreliable(hpage)) It seems we can return here if HPageRawHwpUnreliable as there's nothing to do? Anyway, for what it worth, Reviewed-by: Miaohe Lin <linmiaohe@huawei.com> Thanks. > + ClearPageHWPoison(hpage); > + free_raw_hwp_pages(hpage, true); > } > > /*
On Wed, Jul 13, 2022 at 12:24:46PM +0800, Miaohe Lin wrote: > On 2022/7/12 11:28, Naoya Horiguchi wrote: > > From: Naoya Horiguchi <naoya.horiguchi@nec.com> > > > > Raw error info list needs to be removed when hwpoisoned hugetlb is > > unpoisoned. And unpoison handler needs to know how many errors there > > are in the target hugepage. So add them. > > > > HPageVmemmapOptimized(hpage) and HPageRawHwpUnreliable(hpage)) can't be > > unpoisoned, so let's skip them. > > > > Signed-off-by: Naoya Horiguchi <naoya.horiguchi@nec.com> > > Reported-by: kernel test robot <lkp@intel.com> > > This patch looks good to me with some nits below. > > > --- > ... > > > > -void hugetlb_clear_page_hwpoison(struct page *hpage) > > +static unsigned long free_raw_hwp_pages(struct page *hpage, bool move_flag) > > { > > struct llist_head *head; > > struct llist_node *t, *tnode; > > + unsigned long count = 0; > > > > - if (!HPageRawHwpUnreliable(hpage)) > > - ClearPageHWPoison(hpage); > > + /* > > + * HPageVmemmapOptimized hugepages can't be unpoisoned because > > + * struct pages for tail pages are required to free hwpoisoned > > + * hugepages. HPageRawHwpUnreliable hugepages shouldn't be > > + * unpoisoned by definition. > > + */ > > + if (HPageVmemmapOptimized(hpage) || HPageRawHwpUnreliable(hpage)) > > If move_flag == false, i.e. in unpoison case, tail pages are not touched. So HPageVmemmapOptimized > can be ignored in this case? Or leave it as above to keep the code simple? Oh, right. We can make HPageVmemmapOptimized() more conditional. > > > + return 0; > > head = raw_hwp_list_head(hpage); > > llist_for_each_safe(tnode, t, head->first) { > > struct raw_hwp_page *p = container_of(tnode, struct raw_hwp_page, node); > > > > - SetPageHWPoison(p->page); > > + if (move_flag) > > + SetPageHWPoison(p->page); > > kfree(p); > > + count++; > > } > > llist_del_all(head); > > + return count; > > +} > > + > > +void hugetlb_clear_page_hwpoison(struct page *hpage) > > +{ > > + if (!HPageRawHwpUnreliable(hpage)) > > It seems we can return here if HPageRawHwpUnreliable as there's nothing to do? OK, I'll update this, too. > > Anyway, for what it worth, > > Reviewed-by: Miaohe Lin <linmiaohe@huawei.com> Thank you. - Naoya Horiguchi > > Thanks. > > > + ClearPageHWPoison(hpage); > > + free_raw_hwp_pages(hpage, true); > > } > > > > /*
diff --git a/include/linux/swapops.h b/include/linux/swapops.h index a01aeb3fcc0b..ddc98f96ad2c 100644 --- a/include/linux/swapops.h +++ b/include/linux/swapops.h @@ -498,6 +498,11 @@ static inline void num_poisoned_pages_dec(void) atomic_long_dec(&num_poisoned_pages); } +static inline void num_poisoned_pages_sub(long i) +{ + atomic_long_sub(i, &num_poisoned_pages); +} + #else static inline swp_entry_t make_hwpoison_entry(struct page *page) @@ -518,6 +523,10 @@ static inline struct page *hwpoison_entry_to_page(swp_entry_t entry) static inline void num_poisoned_pages_inc(void) { } + +static inline void num_poisoned_pages_sub(long i) +{ +} #endif static inline int non_swap_entry(swp_entry_t entry) diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 74195c181d69..56fd9d809013 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1720,21 +1720,38 @@ static int hugetlb_set_page_hwpoison(struct page *hpage, struct page *page) return ret; } -void hugetlb_clear_page_hwpoison(struct page *hpage) +static unsigned long free_raw_hwp_pages(struct page *hpage, bool move_flag) { struct llist_head *head; struct llist_node *t, *tnode; + unsigned long count = 0; - if (!HPageRawHwpUnreliable(hpage)) - ClearPageHWPoison(hpage); + /* + * HPageVmemmapOptimized hugepages can't be unpoisoned because + * struct pages for tail pages are required to free hwpoisoned + * hugepages. HPageRawHwpUnreliable hugepages shouldn't be + * unpoisoned by definition. + */ + if (HPageVmemmapOptimized(hpage) || HPageRawHwpUnreliable(hpage)) + return 0; head = raw_hwp_list_head(hpage); llist_for_each_safe(tnode, t, head->first) { struct raw_hwp_page *p = container_of(tnode, struct raw_hwp_page, node); - SetPageHWPoison(p->page); + if (move_flag) + SetPageHWPoison(p->page); kfree(p); + count++; } llist_del_all(head); + return count; +} + +void hugetlb_clear_page_hwpoison(struct page *hpage) +{ + if (!HPageRawHwpUnreliable(hpage)) + ClearPageHWPoison(hpage); + free_raw_hwp_pages(hpage, true); } /* @@ -1878,6 +1895,10 @@ static inline int try_memory_failure_hugetlb(unsigned long pfn, int flags, int * return 0; } +static inline unsigned long free_raw_hwp_pages(struct page *hpage, bool flag) +{ + return 0; +} #endif /* CONFIG_HUGETLB_PAGE */ static int memory_failure_dev_pagemap(unsigned long pfn, int flags, @@ -2283,6 +2304,7 @@ int unpoison_memory(unsigned long pfn) struct page *p; int ret = -EBUSY; int freeit = 0; + unsigned long count = 1; static DEFINE_RATELIMIT_STATE(unpoison_rs, DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); @@ -2330,6 +2352,13 @@ int unpoison_memory(unsigned long pfn) ret = get_hwpoison_page(p, MF_UNPOISON); if (!ret) { + if (PageHuge(p)) { + count = free_raw_hwp_pages(page, false); + if (count == 0) { + ret = -EBUSY; + goto unlock_mutex; + } + } ret = TestClearPageHWPoison(page) ? 0 : -EBUSY; } else if (ret < 0) { if (ret == -EHWPOISON) { @@ -2338,6 +2367,13 @@ int unpoison_memory(unsigned long pfn) unpoison_pr_info("Unpoison: failed to grab page %#lx\n", pfn, &unpoison_rs); } else { + if (PageHuge(p)) { + count = free_raw_hwp_pages(page, false); + if (count == 0) { + ret = -EBUSY; + goto unlock_mutex; + } + } freeit = !!TestClearPageHWPoison(p); put_page(page); @@ -2350,7 +2386,7 @@ int unpoison_memory(unsigned long pfn) unlock_mutex: mutex_unlock(&mf_mutex); if (!ret || freeit) { - num_poisoned_pages_dec(); + num_poisoned_pages_sub(count); unpoison_pr_info("Unpoison: Software-unpoisoned page %#lx\n", page_to_pfn(p), &unpoison_rs); }