2020-01-19 13:15:42

by Wei Yang

[permalink] [raw]
Subject: [PATCH 0/4] mm/page_alloc.c: cleanup on check page

The patch set does some cleanup related to check page:

* extract the common part to do check page
* rename two functions for consistent name convention
* remove two unnecessary variable assignments

No functional change.

Wei Yang (4):
mm/page_alloc.c: extract commom part to check page
mm/page_alloc.c: rename free_pages_check_bad() to
check_free_page_bad()
mm/page_alloc.c: rename free_pages_check() to check_free_page()
mm/page_alloc.c: bad_[reason|flags] is not necessary when PageHWPoison

mm/page_alloc.c | 50 ++++++++++++++++++++++---------------------------
1 file changed, 22 insertions(+), 28 deletions(-)

--
2.17.1


2020-01-19 13:15:59

by Wei Yang

[permalink] [raw]
Subject: [PATCH 3/4] mm/page_alloc.c: rename free_pages_check() to check_free_page()

free_pages_check() is the counterpart of check_new_page(), while
their naming convention is a little different.

Use verb at first and singular form.

Signed-off-by: Wei Yang <[email protected]>
---
mm/page_alloc.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index e2324df1b261..87658a16af07 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1055,7 +1055,7 @@ static void check_free_page_bad(struct page *page)
bad_page(page, bad_reason, bad_flags);
}

-static inline int free_pages_check(struct page *page)
+static inline int check_free_page(struct page *page)
{
if (likely(page_expected_state(page, PAGE_FLAGS_CHECK_AT_FREE)))
return 0;
@@ -1147,7 +1147,7 @@ static __always_inline bool free_pages_prepare(struct page *page,
for (i = 1; i < (1 << order); i++) {
if (compound)
bad += free_tail_pages_check(page, page + i);
- if (unlikely(free_pages_check(page + i))) {
+ if (unlikely(check_free_page(page + i))) {
bad++;
continue;
}
@@ -1159,7 +1159,7 @@ static __always_inline bool free_pages_prepare(struct page *page,
if (memcg_kmem_enabled() && PageKmemcg(page))
__memcg_kmem_uncharge(page, order);
if (check_free)
- bad += free_pages_check(page);
+ bad += check_free_page(page);
if (bad)
return false;

@@ -1206,7 +1206,7 @@ static bool free_pcp_prepare(struct page *page)
static bool bulkfree_pcp_prepare(struct page *page)
{
if (debug_pagealloc_enabled_static())
- return free_pages_check(page);
+ return check_free_page(page);
else
return false;
}
@@ -1227,7 +1227,7 @@ static bool free_pcp_prepare(struct page *page)

static bool bulkfree_pcp_prepare(struct page *page)
{
- return free_pages_check(page);
+ return check_free_page(page);
}
#endif /* CONFIG_DEBUG_VM */

--
2.17.1

2020-01-19 13:16:04

by Wei Yang

[permalink] [raw]
Subject: [PATCH 4/4] mm/page_alloc.c: bad_[reason|flags] is not necessary when PageHWPoison

Since function returns directly, bad_[reason|flags] is not used any
where.

This is a following cleanup for commit e570f56cccd21 ("mm:
check_new_page_bad() directly returns in __PG_HWPOISON case")

Signed-off-by: Wei Yang <[email protected]>
---
mm/page_alloc.c | 2 --
1 file changed, 2 deletions(-)

diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 87658a16af07..2b5e2e156dbf 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -2051,8 +2051,6 @@ static void check_new_page_bad(struct page *page)

bad_reason = __check_page(page);
if (unlikely(page->flags & __PG_HWPOISON)) {
- bad_reason = "HWPoisoned (hardware-corrupted)";
- bad_flags = __PG_HWPOISON;
/* Don't complain about hwpoisoned pages */
page_mapcount_reset(page); /* remove PageBuddy */
return;
--
2.17.1

2020-01-19 13:16:54

by Wei Yang

[permalink] [raw]
Subject: [PATCH 1/4] mm/page_alloc.c: extract commom part to check page

During free and new page, we did some check on the status of page
struct.

There is some common part, just extract them.

Signed-off-by: Wei Yang <[email protected]>
---
mm/page_alloc.c | 36 ++++++++++++++++--------------------
1 file changed, 16 insertions(+), 20 deletions(-)

diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index d047bf7d8fd4..8cd06729169f 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1025,13 +1025,9 @@ static inline bool page_expected_state(struct page *page,
return true;
}

-static void free_pages_check_bad(struct page *page)
+static inline const char *__check_page(struct page *page)
{
- const char *bad_reason;
- unsigned long bad_flags;
-
- bad_reason = NULL;
- bad_flags = 0;
+ const char *bad_reason = NULL;

if (unlikely(atomic_read(&page->_mapcount) != -1))
bad_reason = "nonzero mapcount";
@@ -1039,14 +1035,23 @@ static void free_pages_check_bad(struct page *page)
bad_reason = "non-NULL mapping";
if (unlikely(page_ref_count(page) != 0))
bad_reason = "nonzero _refcount";
- if (unlikely(page->flags & PAGE_FLAGS_CHECK_AT_FREE)) {
- bad_reason = "PAGE_FLAGS_CHECK_AT_FREE flag(s) set";
- bad_flags = PAGE_FLAGS_CHECK_AT_FREE;
- }
#ifdef CONFIG_MEMCG
if (unlikely(page->mem_cgroup))
bad_reason = "page still charged to cgroup";
#endif
+ return bad_reason;
+}
+
+static void free_pages_check_bad(struct page *page)
+{
+ const char *bad_reason = NULL;
+ unsigned long bad_flags = 0;
+
+ bad_reason = __check_page(page);
+ if (unlikely(page->flags & PAGE_FLAGS_CHECK_AT_FREE)) {
+ bad_reason = "PAGE_FLAGS_CHECK_AT_FREE flag(s) set";
+ bad_flags = PAGE_FLAGS_CHECK_AT_FREE;
+ }
bad_page(page, bad_reason, bad_flags);
}

@@ -2044,12 +2049,7 @@ static void check_new_page_bad(struct page *page)
const char *bad_reason = NULL;
unsigned long bad_flags = 0;

- if (unlikely(atomic_read(&page->_mapcount) != -1))
- bad_reason = "nonzero mapcount";
- if (unlikely(page->mapping != NULL))
- bad_reason = "non-NULL mapping";
- if (unlikely(page_ref_count(page) != 0))
- bad_reason = "nonzero _refcount";
+ bad_reason = __check_page(page);
if (unlikely(page->flags & __PG_HWPOISON)) {
bad_reason = "HWPoisoned (hardware-corrupted)";
bad_flags = __PG_HWPOISON;
@@ -2061,10 +2061,6 @@ static void check_new_page_bad(struct page *page)
bad_reason = "PAGE_FLAGS_CHECK_AT_PREP flag set";
bad_flags = PAGE_FLAGS_CHECK_AT_PREP;
}
-#ifdef CONFIG_MEMCG
- if (unlikely(page->mem_cgroup))
- bad_reason = "page still charged to cgroup";
-#endif
bad_page(page, bad_reason, bad_flags);
}

--
2.17.1

2020-01-19 13:17:11

by Wei Yang

[permalink] [raw]
Subject: [PATCH 2/4] mm/page_alloc.c: rename free_pages_check_bad() to check_free_page_bad()

free_pages_check_bad() is the counterpart of check_new_page_bad(), while
their naming convention is a little different.

Use verb at first and singular form.

Signed-off-by: Wei Yang <[email protected]>
---
mm/page_alloc.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 8cd06729169f..e2324df1b261 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1042,7 +1042,7 @@ static inline const char *__check_page(struct page *page)
return bad_reason;
}

-static void free_pages_check_bad(struct page *page)
+static void check_free_page_bad(struct page *page)
{
const char *bad_reason = NULL;
unsigned long bad_flags = 0;
@@ -1061,7 +1061,7 @@ static inline int free_pages_check(struct page *page)
return 0;

/* Something has gone sideways, find it */
- free_pages_check_bad(page);
+ check_free_page_bad(page);
return 1;
}

--
2.17.1

2020-01-19 22:07:27

by David Rientjes

[permalink] [raw]
Subject: Re: [PATCH 1/4] mm/page_alloc.c: extract commom part to check page

On Sun, 19 Jan 2020, Wei Yang wrote:

> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index d047bf7d8fd4..8cd06729169f 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -1025,13 +1025,9 @@ static inline bool page_expected_state(struct page *page,
> return true;
> }
>
> -static void free_pages_check_bad(struct page *page)
> +static inline const char *__check_page(struct page *page)
> {
> - const char *bad_reason;
> - unsigned long bad_flags;
> -
> - bad_reason = NULL;
> - bad_flags = 0;
> + const char *bad_reason = NULL;
>
> if (unlikely(atomic_read(&page->_mapcount) != -1))
> bad_reason = "nonzero mapcount";
> @@ -1039,14 +1035,23 @@ static void free_pages_check_bad(struct page *page)
> bad_reason = "non-NULL mapping";
> if (unlikely(page_ref_count(page) != 0))
> bad_reason = "nonzero _refcount";
> - if (unlikely(page->flags & PAGE_FLAGS_CHECK_AT_FREE)) {
> - bad_reason = "PAGE_FLAGS_CHECK_AT_FREE flag(s) set";
> - bad_flags = PAGE_FLAGS_CHECK_AT_FREE;
> - }
> #ifdef CONFIG_MEMCG
> if (unlikely(page->mem_cgroup))
> bad_reason = "page still charged to cgroup";
> #endif
> + return bad_reason;
> +}
> +
> +static void free_pages_check_bad(struct page *page)
> +{
> + const char *bad_reason = NULL;
> + unsigned long bad_flags = 0;
> +
> + bad_reason = __check_page(page);
> + if (unlikely(page->flags & PAGE_FLAGS_CHECK_AT_FREE)) {
> + bad_reason = "PAGE_FLAGS_CHECK_AT_FREE flag(s) set";
> + bad_flags = PAGE_FLAGS_CHECK_AT_FREE;
> + }
> bad_page(page, bad_reason, bad_flags);
> }
>
> @@ -2044,12 +2049,7 @@ static void check_new_page_bad(struct page *page)
> const char *bad_reason = NULL;
> unsigned long bad_flags = 0;
>
> - if (unlikely(atomic_read(&page->_mapcount) != -1))
> - bad_reason = "nonzero mapcount";
> - if (unlikely(page->mapping != NULL))
> - bad_reason = "non-NULL mapping";
> - if (unlikely(page_ref_count(page) != 0))
> - bad_reason = "nonzero _refcount";
> + bad_reason = __check_page(page);
> if (unlikely(page->flags & __PG_HWPOISON)) {
> bad_reason = "HWPoisoned (hardware-corrupted)";
> bad_flags = __PG_HWPOISON;
> @@ -2061,10 +2061,6 @@ static void check_new_page_bad(struct page *page)
> bad_reason = "PAGE_FLAGS_CHECK_AT_PREP flag set";
> bad_flags = PAGE_FLAGS_CHECK_AT_PREP;
> }
> -#ifdef CONFIG_MEMCG
> - if (unlikely(page->mem_cgroup))
> - bad_reason = "page still charged to cgroup";
> -#endif
> bad_page(page, bad_reason, bad_flags);
> }
>

I think this is compounding a previous problem in these functions: these
are all "if" clauses, not "else if" clauses so they are presumably ordered
based on least significant to most significant (we only see the last
bad_reason that we find). For the page->mem_cgroup check, this leaves
bad_flags set but it doesn't match bad_reason.

Could you instead fix the problem with these functions so that we actually
list *all* the problems with the page rather than only the last
conditional that is true?

2020-01-19 22:09:16

by David Rientjes

[permalink] [raw]
Subject: Re: [PATCH 2/4] mm/page_alloc.c: rename free_pages_check_bad() to check_free_page_bad()

On Sun, 19 Jan 2020, Wei Yang wrote:

> free_pages_check_bad() is the counterpart of check_new_page_bad(), while
> their naming convention is a little different.
>
> Use verb at first and singular form.
>

I think if you agree with the suggestion in patch 1/4 to fix the issue
with bad page reporting that it would likely be better to fold patches 2
and 3 into that change.

2020-01-19 22:09:55

by David Rientjes

[permalink] [raw]
Subject: Re: [PATCH 4/4] mm/page_alloc.c: bad_[reason|flags] is not necessary when PageHWPoison

On Sun, 19 Jan 2020, Wei Yang wrote:

> Since function returns directly, bad_[reason|flags] is not used any
> where.
>
> This is a following cleanup for commit e570f56cccd21 ("mm:
> check_new_page_bad() directly returns in __PG_HWPOISON case")
>
> Signed-off-by: Wei Yang <[email protected]>

Acked-by: David Rientjes <[email protected]>

2020-01-20 00:35:56

by Wei Yang

[permalink] [raw]
Subject: Re: [PATCH 1/4] mm/page_alloc.c: extract commom part to check page

On Sun, Jan 19, 2020 at 02:06:18PM -0800, David Rientjes wrote:
>On Sun, 19 Jan 2020, Wei Yang wrote:
>
>> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
>> index d047bf7d8fd4..8cd06729169f 100644
>> --- a/mm/page_alloc.c
>> +++ b/mm/page_alloc.c
>> @@ -1025,13 +1025,9 @@ static inline bool page_expected_state(struct page *page,
>> return true;
>> }
>>
>> -static void free_pages_check_bad(struct page *page)
>> +static inline const char *__check_page(struct page *page)
>> {
>> - const char *bad_reason;
>> - unsigned long bad_flags;
>> -
>> - bad_reason = NULL;
>> - bad_flags = 0;
>> + const char *bad_reason = NULL;
>>
>> if (unlikely(atomic_read(&page->_mapcount) != -1))
>> bad_reason = "nonzero mapcount";
>> @@ -1039,14 +1035,23 @@ static void free_pages_check_bad(struct page *page)
>> bad_reason = "non-NULL mapping";
>> if (unlikely(page_ref_count(page) != 0))
>> bad_reason = "nonzero _refcount";
>> - if (unlikely(page->flags & PAGE_FLAGS_CHECK_AT_FREE)) {
>> - bad_reason = "PAGE_FLAGS_CHECK_AT_FREE flag(s) set";
>> - bad_flags = PAGE_FLAGS_CHECK_AT_FREE;
>> - }
>> #ifdef CONFIG_MEMCG
>> if (unlikely(page->mem_cgroup))
>> bad_reason = "page still charged to cgroup";
>> #endif
>> + return bad_reason;
>> +}
>> +
>> +static void free_pages_check_bad(struct page *page)
>> +{
>> + const char *bad_reason = NULL;
>> + unsigned long bad_flags = 0;
>> +
>> + bad_reason = __check_page(page);
>> + if (unlikely(page->flags & PAGE_FLAGS_CHECK_AT_FREE)) {
>> + bad_reason = "PAGE_FLAGS_CHECK_AT_FREE flag(s) set";
>> + bad_flags = PAGE_FLAGS_CHECK_AT_FREE;
>> + }
>> bad_page(page, bad_reason, bad_flags);
>> }
>>
>> @@ -2044,12 +2049,7 @@ static void check_new_page_bad(struct page *page)
>> const char *bad_reason = NULL;
>> unsigned long bad_flags = 0;
>>
>> - if (unlikely(atomic_read(&page->_mapcount) != -1))
>> - bad_reason = "nonzero mapcount";
>> - if (unlikely(page->mapping != NULL))
>> - bad_reason = "non-NULL mapping";
>> - if (unlikely(page_ref_count(page) != 0))
>> - bad_reason = "nonzero _refcount";
>> + bad_reason = __check_page(page);
>> if (unlikely(page->flags & __PG_HWPOISON)) {
>> bad_reason = "HWPoisoned (hardware-corrupted)";
>> bad_flags = __PG_HWPOISON;
>> @@ -2061,10 +2061,6 @@ static void check_new_page_bad(struct page *page)
>> bad_reason = "PAGE_FLAGS_CHECK_AT_PREP flag set";
>> bad_flags = PAGE_FLAGS_CHECK_AT_PREP;
>> }
>> -#ifdef CONFIG_MEMCG
>> - if (unlikely(page->mem_cgroup))
>> - bad_reason = "page still charged to cgroup";
>> -#endif
>> bad_page(page, bad_reason, bad_flags);
>> }
>>
>
>I think this is compounding a previous problem in these functions: these
>are all "if" clauses, not "else if" clauses so they are presumably ordered
>based on least significant to most significant (we only see the last
>bad_reason that we find). For the page->mem_cgroup check, this leaves
>bad_flags set but it doesn't match bad_reason.
>

I have thought about this. And curious about the order of those reasons.

>Could you instead fix the problem with these functions so that we actually
>list *all* the problems with the page rather than only the last
>conditional that is true?

Sure, thanks for the suggestion.

--
Wei Yang
Help you, Help me

2020-01-20 00:37:25

by Wei Yang

[permalink] [raw]
Subject: Re: [PATCH 2/4] mm/page_alloc.c: rename free_pages_check_bad() to check_free_page_bad()

On Sun, Jan 19, 2020 at 02:07:04PM -0800, David Rientjes wrote:
>On Sun, 19 Jan 2020, Wei Yang wrote:
>
>> free_pages_check_bad() is the counterpart of check_new_page_bad(), while
>> their naming convention is a little different.
>>
>> Use verb at first and singular form.
>>
>
>I think if you agree with the suggestion in patch 1/4 to fix the issue
>with bad page reporting that it would likely be better to fold patches 2
>and 3 into that change.

I am ok with this, while would it be confusing for review?

--
Wei Yang
Help you, Help me