[RFC,v2,15/16] mm/hwpoison-inject: Rip off duplicated checks
diff mbox series

Message ID 20191017142123.24245-16-osalvador@suse.de
State New
Headers show
Series
  • Hwpoison rework {hard,soft}-offline
Related show

Commit Message

Oscar Salvador Oct. 17, 2019, 2:21 p.m. UTC
memory_failure() already performs the same checks, so leave it
to the main routine.

Signed-off-by: Oscar Salvador <osalvador@suse.de>
---
 mm/hwpoison-inject.c | 33 +++------------------------------
 1 file changed, 3 insertions(+), 30 deletions(-)

Comments

David Hildenbrand Oct. 21, 2019, 9:40 a.m. UTC | #1
On 17.10.19 16:21, Oscar Salvador wrote:
> memory_failure() already performs the same checks, so leave it
> to the main routine.
> 
> Signed-off-by: Oscar Salvador <osalvador@suse.de>
> ---
>   mm/hwpoison-inject.c | 33 +++------------------------------
>   1 file changed, 3 insertions(+), 30 deletions(-)
> 
> diff --git a/mm/hwpoison-inject.c b/mm/hwpoison-inject.c
> index 0c8cdb80fd7d..fdcca3df4283 100644
> --- a/mm/hwpoison-inject.c
> +++ b/mm/hwpoison-inject.c
> @@ -14,49 +14,22 @@ static struct dentry *hwpoison_dir;
>   static int hwpoison_inject(void *data, u64 val)
>   {
>   	unsigned long pfn = val;
> -	struct page *p;
> -	struct page *hpage;
> -	int err;
>   
>   	if (!capable(CAP_SYS_ADMIN))
>   		return -EPERM;
>   
> -	if (!pfn_valid(pfn))
> -		return -ENXIO;
> -
> -	p = pfn_to_page(pfn);
> -	hpage = compound_head(p);
> -
> -	if (!hwpoison_filter_enable)
> -		goto inject;
> -
> -	shake_page(hpage, 0);
> -	/*
> -	 * This implies unable to support non-LRU pages.
> -	 */
> -	if (!PageLRU(hpage) && !PageHuge(p))
> -		return 0;
> -
> -	/*
> -	 * do a racy check to make sure PG_hwpoison will only be set for
> -	 * the targeted owner (or on a free page).
> -	 * memory_failure() will redo the check reliably inside page lock.
> -	 */
> -	err = hwpoison_filter(hpage);
> -	if (err)
> -		return 0;
> -
> -inject:
>   	pr_info("Injecting memory failure at pfn %#lx\n", pfn);
>   	return memory_failure(pfn, 0);
>   }
>   

I explored somewhere already why this code was added:


commit 31d3d3484f9bd263925ecaa341500ac2df3a5d9b
Author: Wu Fengguang <fengguang.wu@intel.com>
Date:   Wed Dec 16 12:19:59 2009 +0100

    HWPOISON: limit hwpoison injector to known page types
    
    __memory_failure()'s workflow is
    
            set PG_hwpoison
            //...
            unset PG_hwpoison if didn't pass hwpoison filter
    
    That could kill unrelated process if it happens to page fault on the
    page with the (temporary) PG_hwpoison. The race should be big enough to
    appear in stress tests.
    
    Fix it by grabbing the page and checking filter at inject time.  This
    also avoids the very noisy "Injecting memory failure..." messages.
    
    - we don't touch madvise() based injection, because the filters are
      generally not necessary for it.
    - if we want to apply the filters to h/w aided injection, we'd better to
      rearrange the logic in __memory_failure() instead of this patch.
    
    AK: fix documentation, use drain all, cleanups


You should justify why it is okay to do rip that code out now.
It's not just duplicate checks.

Was the documented race fixed?
Will we fix the race within memory_failure() later?
Don't we care?

Also, you should add that this fixes the access of uninitialized memmaps
now and makes the interface work correctly with devmem.
Oscar Salvador Oct. 22, 2019, 7:57 a.m. UTC | #2
On Mon, Oct 21, 2019 at 11:40:39AM +0200, David Hildenbrand wrote:
> I explored somewhere already why this code was added:
> 
> 
> commit 31d3d3484f9bd263925ecaa341500ac2df3a5d9b
> Author: Wu Fengguang <fengguang.wu@intel.com>
> Date:   Wed Dec 16 12:19:59 2009 +0100
> 
>     HWPOISON: limit hwpoison injector to known page types
>     
>     __memory_failure()'s workflow is
>     
>             set PG_hwpoison
>             //...
>             unset PG_hwpoison if didn't pass hwpoison filter
>     
>     That could kill unrelated process if it happens to page fault on the
>     page with the (temporary) PG_hwpoison. The race should be big enough to
>     appear in stress tests.
>     
>     Fix it by grabbing the page and checking filter at inject time.  This
>     also avoids the very noisy "Injecting memory failure..." messages.
>     
>     - we don't touch madvise() based injection, because the filters are
>       generally not necessary for it.
>     - if we want to apply the filters to h/w aided injection, we'd better to
>       rearrange the logic in __memory_failure() instead of this patch.
>     
>     AK: fix documentation, use drain all, cleanups
> 
> 
> You should justify why it is okay to do rip that code out now.
> It's not just duplicate checks.
> 
> Was the documented race fixed?
> Will we fix the race within memory_failure() later?
> Don't we care?
> 
> Also, you should add that this fixes the access of uninitialized memmaps
> now and makes the interface work correctly with devmem.

Thanks for bringuing this up David.
I guess I was carried away.

Since I have to do another re-spin to re-work a couple of things, I will
work on this as well.

Patch
diff mbox series

diff --git a/mm/hwpoison-inject.c b/mm/hwpoison-inject.c
index 0c8cdb80fd7d..fdcca3df4283 100644
--- a/mm/hwpoison-inject.c
+++ b/mm/hwpoison-inject.c
@@ -14,49 +14,22 @@  static struct dentry *hwpoison_dir;
 static int hwpoison_inject(void *data, u64 val)
 {
 	unsigned long pfn = val;
-	struct page *p;
-	struct page *hpage;
-	int err;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	if (!pfn_valid(pfn))
-		return -ENXIO;
-
-	p = pfn_to_page(pfn);
-	hpage = compound_head(p);
-
-	if (!hwpoison_filter_enable)
-		goto inject;
-
-	shake_page(hpage, 0);
-	/*
-	 * This implies unable to support non-LRU pages.
-	 */
-	if (!PageLRU(hpage) && !PageHuge(p))
-		return 0;
-
-	/*
-	 * do a racy check to make sure PG_hwpoison will only be set for
-	 * the targeted owner (or on a free page).
-	 * memory_failure() will redo the check reliably inside page lock.
-	 */
-	err = hwpoison_filter(hpage);
-	if (err)
-		return 0;
-
-inject:
 	pr_info("Injecting memory failure at pfn %#lx\n", pfn);
 	return memory_failure(pfn, 0);
 }
 
 static int hwpoison_unpoison(void *data, u64 val)
 {
+	unsigned long pfn = val;
+
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	return unpoison_memory(val);
+	return unpoison_memory(pfn);
 }
 
 DEFINE_SIMPLE_ATTRIBUTE(hwpoison_fops, NULL, hwpoison_inject, "%lli\n");