[PATCH] (for testing) revert change around removing MF_COUNT_INCREASED

From: Naoya Horiguchi
Date: Wed Aug 05 2020 - 12:29:08 EST


revert the following patches
- mm,madvise: call soft_offline_page() without MF_COUNT_INCREASED
- mm,madvise: Refactor madvise_inject_error
- mm,hwpoison: remove MF_COUNT_INCREASED
- mm,hwpoison: remove flag argument from soft offline functions

Signed-off-by: Naoya Horiguchi <naoya.horiguchi@xxxxxxx>
---
drivers/base/memory.c | 2 +-
include/linux/mm.h | 9 +++++----
mm/madvise.c | 36 +++++++++++++++++++-----------------
mm/memory-failure.c | 31 ++++++++++++++++++++-----------
4 files changed, 45 insertions(+), 33 deletions(-)

diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 3e6d27c9dff6..4db3c660de83 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -463,7 +463,7 @@ static ssize_t soft_offline_page_store(struct device *d=
ev,
if (kstrtoull(buf, 0, &pfn) < 0)
return -EINVAL;
pfn >>=3D PAGE_SHIFT;
- ret =3D soft_offline_page(pfn);
+ ret =3D soft_offline_page(pfn, 0);
return ret =3D=3D 0 ? count : ret;
}
=20
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 4f12b2465e80..442921a004a2 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2976,9 +2976,10 @@ void register_page_bootmem_memmap(unsigned long sect=
ion_nr, struct page *map,
unsigned long nr_pages);
=20
enum mf_flags {
- MF_ACTION_REQUIRED =3D 1 << 0,
- MF_MUST_KILL =3D 1 << 1,
- MF_SOFT_OFFLINE =3D 1 << 2,
+ MF_COUNT_INCREASED =3D 1 << 0,
+ MF_ACTION_REQUIRED =3D 1 << 1,
+ MF_MUST_KILL =3D 1 << 2,
+ MF_SOFT_OFFLINE =3D 1 << 3,
};
extern int memory_failure(unsigned long pfn, int flags);
extern void memory_failure_queue(unsigned long pfn, int flags);
@@ -2988,7 +2989,7 @@ extern int sysctl_memory_failure_early_kill;
extern int sysctl_memory_failure_recovery;
extern void shake_page(struct page *p, int access);
extern atomic_long_t num_poisoned_pages __read_mostly;
-extern int soft_offline_page(unsigned long pfn);
+extern int soft_offline_page(unsigned long pfn, int flags);
=20
=20
/*
diff --git a/mm/madvise.c b/mm/madvise.c
index 843f6fad3b89..5fa5f66468b3 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -886,15 +886,16 @@ static long madvise_remove(struct vm_area_struct *vma=
,
static int madvise_inject_error(int behavior,
unsigned long start, unsigned long end)
{
+ struct page *page;
struct zone *zone;
unsigned long size;
=20
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
=20
+
for (; start < end; start +=3D size) {
unsigned long pfn;
- struct page *page;
int ret;
=20
ret =3D get_user_pages_fast(start, 1, 0, &page);
@@ -909,26 +910,27 @@ static int madvise_inject_error(int behavior,
*/
size =3D page_size(compound_head(page));
=20
- /*
- * The get_user_pages_fast() is just to get the pfn of the
- * given address, and the refcount has nothing to do with
- * what we try to test, so it should be released immediately.
- * This is racy but it's intended because the real hardware
- * errors could happen at any moment and memory error handlers
- * must properly handle the race.
- */
- put_page(page);
-
if (behavior =3D=3D MADV_SOFT_OFFLINE) {
pr_info("Soft offlining pfn %#lx at process virtual address %#lx\n",
- pfn, start);
- ret =3D soft_offline_page(pfn);
- } else {
- pr_info("Injecting memory failure for pfn %#lx at process virtual addre=
ss %#lx\n",
- pfn, start);
- ret =3D memory_failure(pfn, 0);
+ pfn, start);
+
+ ret =3D soft_offline_page(pfn, MF_COUNT_INCREASED);
+ if (ret)
+ return ret;
+ continue;
}
=20
+ pr_info("Injecting memory failure for pfn %#lx at process virtual addres=
s %#lx\n",
+ pfn, start);
+
+ /*
+ * Drop the page reference taken by get_user_pages_fast(). In
+ * the absence of MF_COUNT_INCREASED the memory_failure()
+ * routine is responsible for pinning the page to prevent it
+ * from being released back to the page allocator.
+ */
+ put_page(page);
+ ret =3D memory_failure(pfn, 0);
if (ret)
return ret;
}
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index a229d4694954..fd50a6f9a60d 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1167,7 +1167,7 @@ static int memory_failure_hugetlb(unsigned long pfn, =
int flags)
=20
num_poisoned_pages_inc();
=20
- if (!get_hwpoison_page(p)) {
+ if (!(flags & MF_COUNT_INCREASED) && !get_hwpoison_page(p)) {
/*
* Check "filter hit" and "race with other subpage."
*/
@@ -1363,7 +1363,7 @@ int memory_failure(unsigned long pfn, int flags)
* In fact it's dangerous to directly bump up page count from 0,
* that may make page_ref_freeze()/page_ref_unfreeze() mismatch.
*/
- if (!get_hwpoison_page(p)) {
+ if (!(flags & MF_COUNT_INCREASED) && !get_hwpoison_page(p)) {
if (is_free_buddy_page(p)) {
action_result(pfn, MF_MSG_BUDDY, MF_DELAYED);
return 0;
@@ -1392,7 +1392,10 @@ int memory_failure(unsigned long pfn, int flags)
shake_page(p, 0);
/* shake_page could have turned it free. */
if (!PageLRU(p) && is_free_buddy_page(p)) {
- action_result(pfn, MF_MSG_BUDDY_2ND, MF_DELAYED);
+ if (flags & MF_COUNT_INCREASED)
+ action_result(pfn, MF_MSG_BUDDY, MF_DELAYED);
+ else
+ action_result(pfn, MF_MSG_BUDDY_2ND, MF_DELAYED);
return 0;
}
=20
@@ -1540,7 +1543,7 @@ static void memory_failure_work_func(struct work_stru=
ct *work)
if (!gotten)
break;
if (entry.flags & MF_SOFT_OFFLINE)
- soft_offline_page(entry.pfn);
+ soft_offline_page(entry.pfn, entry.flags);
else
memory_failure(entry.pfn, entry.flags);
}
@@ -1679,10 +1682,13 @@ EXPORT_SYMBOL(unpoison_memory);
* that is not free, and 1 for any other page type.
* For 1 the page is returned with increased page count, otherwise not.
*/
-static int __get_any_page(struct page *p, unsigned long pfn)
+static int __get_any_page(struct page *p, unsigned long pfn, int flags)
{
int ret;
=20
+ if (flags & MF_COUNT_INCREASED)
+ return 1;
+
/*
* When the target page is a free hugepage, just remove it
* from free hugepage list.
@@ -1709,12 +1715,12 @@ static int __get_any_page(struct page *p, unsigned =
long pfn)
return ret;
}
=20
-static int get_any_page(struct page *page, unsigned long pfn)
+static int get_any_page(struct page *page, unsigned long pfn, int flags)
{
- int ret =3D __get_any_page(page, pfn);
+ int ret =3D __get_any_page(page, pfn, flags);
=20
if (ret =3D=3D -EBUSY)
- ret =3D __get_any_page(page, pfn);
+ ret =3D __get_any_page(page, pfn, flags);
=20
if (ret =3D=3D 1 && !PageHuge(page) &&
!PageLRU(page) && !__PageMovable(page)) {
@@ -1727,7 +1733,7 @@ static int get_any_page(struct page *page, unsigned l=
ong pfn)
/*
* Did it turn free?
*/
- ret =3D __get_any_page(page, pfn);
+ ret =3D __get_any_page(page, pfn, 0);
if (ret =3D=3D 1 && !PageLRU(page)) {
/* Drop page reference which is from __get_any_page() */
put_page(page);
@@ -1869,6 +1875,7 @@ static int soft_offline_free_page(struct page *page)
/**
* soft_offline_page - Soft offline a page.
* @pfn: pfn to soft-offline
+ * @flags: flags. Same as memory_failure().
*
* Returns 0 on success, otherwise negated errno.
*
@@ -1887,7 +1894,7 @@ static int soft_offline_free_page(struct page *page)
* This is not a 100% solution for all memory, but tries to be
* ``good enough'' for the majority of memory.
*/
-int soft_offline_page(unsigned long pfn)
+int soft_offline_page(unsigned long pfn, int flags)
{
int ret;
struct page *page;
@@ -1901,11 +1908,13 @@ int soft_offline_page(unsigned long pfn)
=20
if (PageHWPoison(page)) {
pr_info("soft offline: %#lx page already poisoned\n", pfn);
+ if (flags & MF_COUNT_INCREASED)
+ put_page(page);
return 0;
}
=20
get_online_mems();
- ret =3D get_any_page(page, pfn);
+ ret =3D get_any_page(page, pfn, flags);
put_online_mems();
=20
if (ret > 0)
--=20
2.25.1