Thread (7 messages) read the whole thread 7 messages, 5 authors, 2021-03-18

Re: File THP and HWPoison

From: HORIGUCHI NAOYA (堀口 直也) <hidden>
Date: 2021-03-18 17:25:50

On Thu, Mar 18, 2021 at 02:57:16PM +0000, Matthew Wilcox wrote:
On Thu, Mar 18, 2021 at 05:08:43PM +0300, Kirill A. Shutemov wrote:
quoted
On Tue, Mar 16, 2021 at 02:09:47PM +0000, Matthew Wilcox wrote:
quoted
If we get a memory failure in the middle of a file THP, I think we handle
it poorly.

int memory_failure(unsigned long pfn, int flags)
...
        if (TestSetPageHWPoison(p)) {
...
        orig_head = hpage = compound_head(p);
...
        if (PageTransHuge(hpage)) {
                if (try_to_split_thp_page(p, "Memory Failure") < 0) {
                        action_result(pfn, MF_MSG_UNSPLIT_THP, MF_IGNORED);
                        return -EBUSY;
                }

static int try_to_split_thp_page(struct page *page, const char *msg)
{
        lock_page(page);
        if (!PageAnon(page) || unlikely(split_huge_page(page))) {
                unsigned long pfn = page_to_pfn(page);

                unlock_page(page);
                if (!PageAnon(page))
                        pr_info("%s: %#lx: non anonymous thp\n", msg, pfn);
                else
                        pr_info("%s: %#lx: thp split failed\n", msg, pfn);
                put_page(page);
                return -EBUSY;

So (for some reason) we don't even try to split a file THP.  But then,
if we take a page fault on a file THP:

static struct page *next_uptodate_page(struct page *page,
...
                if (PageHWPoison(page))
                        goto skip;
(... but we're only testing the head page here, which isn't necessarily
the one which got the error ...)

        if (pmd_none(*vmf->pmd) && PageTransHuge(page)) {
            vm_fault_t ret = do_set_pmd(vmf, page);

So we now map the PMD-sized page into userspace, even though it has a
HWPoison in it.

I think there are two things that we should be doing:

1. Attempt to split THPs which are file-backed.  That makes most of this
problem disappear because there won't be THPs with HWPoison, mostly.
+Naoya. Could you give more context here?
Recently, I tried to address the problem on
https://lore.kernel.org/linux-mm/20210209062128.453814-1-nao.horiguchi@gmail.com/ (local)
but the patch was found incorrect because the related page table entries disappeared
after split_huge_page() succeeded.  I thought I'm going to study more, but
didn't make it this week because I looked at other review requests.

A pmd mapping for anonymous thp is replaced with 512 pte mappings by
split_huge_page(), so I'm wondering why we don't do the same for shmem thp.
I did some git archaeology and found this check was introduced in
7f6bf39bbdd1 ("mm/hwpoison: fix panic due to split huge zero page") where
it wasn't intended to catch _file_ pages at all, but the zero page.
I suspect that nobody thought to look at this when introducing THP
for shmem.
Yes, 7f6bf39bbdd1 was worked before thp page cache, so we did not consider
it at that time.

Thanks,
Naoya Horiguchi
quoted
quoted
2. When the THP fails to split, use a spare page flag to indicate that
the THP contains a HWPoison bit in one of its subpages.  There are a
lot of PF_SECOND flags available for this purpose.

but I know almost nothing about the memory-failure subsystem and I'm
still learning all the complexities of THPs, so it's entirely possible
I've overlooked something important.
I wounder if it would be cleaner to switch PG_hwpoison to PF_HEAD: if
split failed we posion whole compound page. Yes, we will waste more
memory, but it makes it much cleaner for user: just check if the page is
poisoned.
I think that's a poor quality implementation ... it'd cause processes
to die that weren't even touching the page that had hwpoison.  Using
a PF_SECOND bit lets us do the check as cheaply as if we made hwpoison
PF_HEAD.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help