diff mbox series

[3/3] mm/memory-failure.c: dissolve truncated hugetlb page

Message ID 20220407130352.15618-4-linmiaohe@huawei.com (mailing list archive)
State New
Headers show
Series A few fixup and cleanup patches for memory failure | expand

Commit Message

Miaohe Lin April 7, 2022, 1:03 p.m. UTC
If me_huge_page meets a truncated huge page, hpage won't be dissolved
even if we hold the last refcnt. It's because the truncated huge page
has NULL page_mapping while it's not anonymous page too. Thus we lose
the last chance to dissolve it into buddy to save healthy subpages.
Remove PageAnon check to handle these huge pages too.

Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
---
 mm/memory-failure.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

Comments

HORIGUCHI NAOYA(堀口 直也) April 11, 2022, 1:13 p.m. UTC | #1
Hi Miaohe,

On Thu, Apr 07, 2022 at 09:03:52PM +0800, Miaohe Lin wrote:
> If me_huge_page meets a truncated huge page, hpage won't be dissolved

I might not understand correctly what "truncated huge page" means.  If it
means the page passed to me_huge_page() and truncate_error_page() is called
on it, the else branch you're trying to update is not chosen, so maybe it
sounds irrelevant to me?  Could you elaborate it or share the procedure to
reproduce the case you care about?

> even if we hold the last refcnt. It's because the truncated huge page
> has NULL page_mapping while it's not anonymous page too. Thus we lose
> the last chance to dissolve it into buddy to save healthy subpages.
> Remove PageAnon check to handle these huge pages too.
> 
> Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
> ---
>  mm/memory-failure.c | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/mm/memory-failure.c b/mm/memory-failure.c
> index bd563f47630c..3f054dbb169d 100644
> --- a/mm/memory-failure.c
> +++ b/mm/memory-failure.c
> @@ -1046,8 +1046,7 @@ static int me_huge_page(struct page_state *ps, struct page *p)
>  		 * hugepage, so we can free and dissolve it into buddy to
>  		 * save healthy subpages.
>  		 */
> -		if (PageAnon(hpage))
> -			put_page(hpage);

I think that the reason of this "if (PageAnon(hpage))" is to not remove
hugepages for hugetlbfs files.  Unlike anonymous hugepage, it can be
accessed from file after error handling, so we can't simply dissolve it
because otherwise another process reading the hugepage sees zeroed one
without knowing the memory error.

Thanks,
Naoya Horiguchi

> +		put_page(hpage);
>  		if (__page_handle_poison(p)) {
>  			page_ref_inc(p);
>  			res = MF_RECOVERED;
> -- 
> 2.23.0
Miaohe Lin April 12, 2022, 2:47 a.m. UTC | #2
On 2022/4/11 21:13, HORIGUCHI NAOYA(堀口 直也) wrote:
> Hi Miaohe,
> 
> On Thu, Apr 07, 2022 at 09:03:52PM +0800, Miaohe Lin wrote:
>> If me_huge_page meets a truncated huge page, hpage won't be dissolved
> 
> I might not understand correctly what "truncated huge page" means.  If it
> means the page passed to me_huge_page() and truncate_error_page() is called
> on it, the else branch you're trying to update is not chosen, so maybe it
> sounds irrelevant to me?  Could you elaborate it or share the procedure to
> reproduce the case you care about?

Sorry for making confusing. What 'truncated hugetlb page' means is that a hugepage is
truncated but still on the way to free. So HPageMigratable is still set and we might
come across it here. Does this make sense for you?

> 
>> even if we hold the last refcnt. It's because the truncated huge page
>> has NULL page_mapping while it's not anonymous page too. Thus we lose
>> the last chance to dissolve it into buddy to save healthy subpages.
>> Remove PageAnon check to handle these huge pages too.
>>
>> Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
>> ---
>>  mm/memory-failure.c | 3 +--
>>  1 file changed, 1 insertion(+), 2 deletions(-)
>>
>> diff --git a/mm/memory-failure.c b/mm/memory-failure.c
>> index bd563f47630c..3f054dbb169d 100644
>> --- a/mm/memory-failure.c
>> +++ b/mm/memory-failure.c
>> @@ -1046,8 +1046,7 @@ static int me_huge_page(struct page_state *ps, struct page *p)
>>  		 * hugepage, so we can free and dissolve it into buddy to
>>  		 * save healthy subpages.
>>  		 */
>> -		if (PageAnon(hpage))
>> -			put_page(hpage);
> 
> I think that the reason of this "if (PageAnon(hpage))" is to not remove
> hugepages for hugetlbfs files.  Unlike anonymous hugepage, it can be
> accessed from file after error handling, so we can't simply dissolve it
> because otherwise another process reading the hugepage sees zeroed one
> without knowing the memory error.

In this branch, we have precondition that page_mapping is NULL. So it can't be hugepages
for hugetlbfs files. It should be anonymous hugepages in most cases. If it's not anonymous
hugepages too, i.e. (!page_mapping(hpage) && !PageAnon(hpage)), it could be free hugepages
or 'truncated hugetlb page'. But we have already handled the free hugepages case, it should
be 'truncated hugetlb page' here. Since it's on the way to free, we should put the refcnt
to increase the chance that we can free and dissolve it into buddy to save healthy subpages.
Or am I miss something?

Thanks!

> 
> Thanks,
> Naoya Horiguchi
> 
>> +		put_page(hpage);
>>  		if (__page_handle_poison(p)) {
>>  			page_ref_inc(p);
>>  			res = MF_RECOVERED;
>> -- 
>> 2.23.0
HORIGUCHI NAOYA(堀口 直也) April 12, 2022, 5:59 a.m. UTC | #3
On Tue, Apr 12, 2022 at 10:47:53AM +0800, Miaohe Lin wrote:
> On 2022/4/11 21:13, HORIGUCHI NAOYA(堀口 直也) wrote:
> > Hi Miaohe,
> > 
> > On Thu, Apr 07, 2022 at 09:03:52PM +0800, Miaohe Lin wrote:
> >> If me_huge_page meets a truncated huge page, hpage won't be dissolved
> > 
> > I might not understand correctly what "truncated huge page" means.  If it
> > means the page passed to me_huge_page() and truncate_error_page() is called
> > on it, the else branch you're trying to update is not chosen, so maybe it
> > sounds irrelevant to me?  Could you elaborate it or share the procedure to
> > reproduce the case you care about?
> 
> Sorry for making confusing. What 'truncated hugetlb page' means is that a hugepage is
> truncated but still on the way to free. So HPageMigratable is still set and we might
> come across it here. Does this make sense for you?

Yes, it does. Thank you.

> 
> > 
> >> even if we hold the last refcnt. It's because the truncated huge page
> >> has NULL page_mapping while it's not anonymous page too. Thus we lose
> >> the last chance to dissolve it into buddy to save healthy subpages.
> >> Remove PageAnon check to handle these huge pages too.
> >>
> >> Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
> >> ---
> >>  mm/memory-failure.c | 3 +--
> >>  1 file changed, 1 insertion(+), 2 deletions(-)
> >>
> >> diff --git a/mm/memory-failure.c b/mm/memory-failure.c
> >> index bd563f47630c..3f054dbb169d 100644
> >> --- a/mm/memory-failure.c
> >> +++ b/mm/memory-failure.c
> >> @@ -1046,8 +1046,7 @@ static int me_huge_page(struct page_state *ps, struct page *p)
> >>  		 * hugepage, so we can free and dissolve it into buddy to
> >>  		 * save healthy subpages.
> >>  		 */
> >> -		if (PageAnon(hpage))
> >> -			put_page(hpage);
> > 
> > I think that the reason of this "if (PageAnon(hpage))" is to not remove
> > hugepages for hugetlbfs files.  Unlike anonymous hugepage, it can be
> > accessed from file after error handling, so we can't simply dissolve it
> > because otherwise another process reading the hugepage sees zeroed one
> > without knowing the memory error.
> 
> In this branch, we have precondition that page_mapping is NULL. So it can't be hugepages
> for hugetlbfs files. It should be anonymous hugepages in most cases. If it's not anonymous
> hugepages too, i.e. (!page_mapping(hpage) && !PageAnon(hpage)), it could be free hugepages
> or 'truncated hugetlb page'. But we have already handled the free hugepages case, it should
> be 'truncated hugetlb page' here. Since it's on the way to free, we should put the refcnt
> to increase the chance that we can free and dissolve it into buddy to save healthy subpages.
> Or am I miss something?

No, it sounds correct.  So I agree with removing the "if".  Could you also
update the inline comment just above it in the next version?  We no longer
need to limitedly mention "anonymous hugepage".

Thanks,
Naoya Horiguchi
Miaohe Lin April 12, 2022, 6:10 a.m. UTC | #4
On 2022/4/12 13:59, HORIGUCHI NAOYA(堀口 直也) wrote:
> On Tue, Apr 12, 2022 at 10:47:53AM +0800, Miaohe Lin wrote:
>> On 2022/4/11 21:13, HORIGUCHI NAOYA(堀口 直也) wrote:
>>> Hi Miaohe,
>>>
>>> On Thu, Apr 07, 2022 at 09:03:52PM +0800, Miaohe Lin wrote:
>>>> If me_huge_page meets a truncated huge page, hpage won't be dissolved
>>>
>>> I might not understand correctly what "truncated huge page" means.  If it
>>> means the page passed to me_huge_page() and truncate_error_page() is called
>>> on it, the else branch you're trying to update is not chosen, so maybe it
>>> sounds irrelevant to me?  Could you elaborate it or share the procedure to
>>> reproduce the case you care about?
>>
>> Sorry for making confusing. What 'truncated hugetlb page' means is that a hugepage is
>> truncated but still on the way to free. So HPageMigratable is still set and we might
>> come across it here. Does this make sense for you?
> 
> Yes, it does. Thank you.
> 
>>
>>>
>>>> even if we hold the last refcnt. It's because the truncated huge page
>>>> has NULL page_mapping while it's not anonymous page too. Thus we lose
>>>> the last chance to dissolve it into buddy to save healthy subpages.
>>>> Remove PageAnon check to handle these huge pages too.
>>>>
>>>> Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
>>>> ---
>>>>  mm/memory-failure.c | 3 +--
>>>>  1 file changed, 1 insertion(+), 2 deletions(-)
>>>>
>>>> diff --git a/mm/memory-failure.c b/mm/memory-failure.c
>>>> index bd563f47630c..3f054dbb169d 100644
>>>> --- a/mm/memory-failure.c
>>>> +++ b/mm/memory-failure.c
>>>> @@ -1046,8 +1046,7 @@ static int me_huge_page(struct page_state *ps, struct page *p)
>>>>  		 * hugepage, so we can free and dissolve it into buddy to
>>>>  		 * save healthy subpages.
>>>>  		 */
>>>> -		if (PageAnon(hpage))
>>>> -			put_page(hpage);
>>>
>>> I think that the reason of this "if (PageAnon(hpage))" is to not remove
>>> hugepages for hugetlbfs files.  Unlike anonymous hugepage, it can be
>>> accessed from file after error handling, so we can't simply dissolve it
>>> because otherwise another process reading the hugepage sees zeroed one
>>> without knowing the memory error.
>>
>> In this branch, we have precondition that page_mapping is NULL. So it can't be hugepages
>> for hugetlbfs files. It should be anonymous hugepages in most cases. If it's not anonymous
>> hugepages too, i.e. (!page_mapping(hpage) && !PageAnon(hpage)), it could be free hugepages
>> or 'truncated hugetlb page'. But we have already handled the free hugepages case, it should
>> be 'truncated hugetlb page' here. Since it's on the way to free, we should put the refcnt
>> to increase the chance that we can free and dissolve it into buddy to save healthy subpages.
>> Or am I miss something?
> 
> No, it sounds correct.  So I agree with removing the "if".  Could you also
> update the inline comment just above it in the next version?  We no longer
> need to limitedly mention "anonymous hugepage".

Sure. Will do it in next version. Many thanks!

> 
> Thanks,
> Naoya Horiguchi
>
diff mbox series

Patch

diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index bd563f47630c..3f054dbb169d 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1046,8 +1046,7 @@  static int me_huge_page(struct page_state *ps, struct page *p)
 		 * hugepage, so we can free and dissolve it into buddy to
 		 * save healthy subpages.
 		 */
-		if (PageAnon(hpage))
-			put_page(hpage);
+		put_page(hpage);
 		if (__page_handle_poison(p)) {
 			page_ref_inc(p);
 			res = MF_RECOVERED;