License cleanup: add SPDX GPL-2.0 license identifier to files with no license
Many source files in the tree are missing licensing information, which
makes it harder for compliance tools to determine the correct license.
By default all files without license information are under the default
license of the kernel, which is GPL version 2.
Update the files which contain no license information with the 'GPL-2.0'
SPDX license identifier. The SPDX identifier is a legally binding
shorthand, which can be used instead of the full boiler plate text.
This patch is based on work done by Thomas Gleixner and Kate Stewart and
Philippe Ombredanne.
How this work was done:
Patches were generated and checked against linux-4.14-rc6 for a subset of
the use cases:
- file had no licensing information it it.
- file was a */uapi/* one with no licensing information in it,
- file was a */uapi/* one with existing licensing information,
Further patches will be generated in subsequent months to fix up cases
where non-standard license headers were used, and references to license
had to be inferred by heuristics based on keywords.
The analysis to determine which SPDX License Identifier to be applied to
a file was done in a spreadsheet of side by side results from of the
output of two independent scanners (ScanCode & Windriver) producing SPDX
tag:value files created by Philippe Ombredanne. Philippe prepared the
base worksheet, and did an initial spot review of a few 1000 files.
The 4.13 kernel was the starting point of the analysis with 60,537 files
assessed. Kate Stewart did a file by file comparison of the scanner
results in the spreadsheet to determine which SPDX license identifier(s)
to be applied to the file. She confirmed any determination that was not
immediately clear with lawyers working with the Linux Foundation.
Criteria used to select files for SPDX license identifier tagging was:
- Files considered eligible had to be source code files.
- Make and config files were included as candidates if they contained >5
lines of source
- File already had some variant of a license header in it (even if <5
lines).
All documentation files were explicitly excluded.
The following heuristics were used to determine which SPDX license
identifiers to apply.
- when both scanners couldn't find any license traces, file was
considered to have no license information in it, and the top level
COPYING file license applied.
For non */uapi/* files that summary was:
SPDX license identifier # files
---------------------------------------------------|-------
GPL-2.0 11139
and resulted in the first patch in this series.
If that file was a */uapi/* path one, it was "GPL-2.0 WITH
Linux-syscall-note" otherwise it was "GPL-2.0". Results of that was:
SPDX license identifier # files
---------------------------------------------------|-------
GPL-2.0 WITH Linux-syscall-note 930
and resulted in the second patch in this series.
- if a file had some form of licensing information in it, and was one
of the */uapi/* ones, it was denoted with the Linux-syscall-note if
any GPL family license was found in the file or had no licensing in
it (per prior point). Results summary:
SPDX license identifier # files
---------------------------------------------------|------
GPL-2.0 WITH Linux-syscall-note 270
GPL-2.0+ WITH Linux-syscall-note 169
((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) 21
((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) 17
LGPL-2.1+ WITH Linux-syscall-note 15
GPL-1.0+ WITH Linux-syscall-note 14
((GPL-2.0+ WITH Linux-syscall-note) OR BSD-3-Clause) 5
LGPL-2.0+ WITH Linux-syscall-note 4
LGPL-2.1 WITH Linux-syscall-note 3
((GPL-2.0 WITH Linux-syscall-note) OR MIT) 3
((GPL-2.0 WITH Linux-syscall-note) AND MIT) 1
and that resulted in the third patch in this series.
- when the two scanners agreed on the detected license(s), that became
the concluded license(s).
- when there was disagreement between the two scanners (one detected a
license but the other didn't, or they both detected different
licenses) a manual inspection of the file occurred.
- In most cases a manual inspection of the information in the file
resulted in a clear resolution of the license that should apply (and
which scanner probably needed to revisit its heuristics).
- When it was not immediately clear, the license identifier was
confirmed with lawyers working with the Linux Foundation.
- If there was any question as to the appropriate license identifier,
the file was flagged for further research and to be revisited later
in time.
In total, over 70 hours of logged manual review was done on the
spreadsheet to determine the SPDX license identifiers to apply to the
source files by Kate, Philippe, Thomas and, in some cases, confirmation
by lawyers working with the Linux Foundation.
Kate also obtained a third independent scan of the 4.13 code base from
FOSSology, and compared selected files where the other two scanners
disagreed against that SPDX file, to see if there was new insights. The
Windriver scanner is based on an older version of FOSSology in part, so
they are related.
Thomas did random spot checks in about 500 files from the spreadsheets
for the uapi headers and agreed with SPDX license identifier in the
files he inspected. For the non-uapi files Thomas did random spot checks
in about 15000 files.
In initial set of patches against 4.14-rc6, 3 files were found to have
copy/paste license identifier errors, and have been fixed to reflect the
correct identifier.
Additionally Philippe spent 10 hours this week doing a detailed manual
inspection and review of the 12,461 patched files from the initial patch
version early this week with:
- a full scancode scan run, collecting the matched texts, detected
license ids and scores
- reviewing anything where there was a license detected (about 500+
files) to ensure that the applied SPDX license was correct
- reviewing anything where there was no detection but the patch license
was not GPL-2.0 WITH Linux-syscall-note to ensure that the applied
SPDX license was correct
This produced a worksheet with 20 files needing minor correction. This
worksheet was then exported into 3 different .csv files for the
different types of files to be modified.
These .csv files were then reviewed by Greg. Thomas wrote a script to
parse the csv files and add the proper SPDX tag to the file, in the
format that the file expected. This script was further refined by Greg
based on the output to detect more types of files automatically and to
distinguish between header and source .c files (which need different
comment types.) Finally Greg ran the script using the .csv files to
generate the patches.
Reviewed-by: Kate Stewart <kstewart@linuxfoundation.org>
Reviewed-by: Philippe Ombredanne <pombredanne@nexb.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2017-11-01 22:07:57 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2007-10-16 16:26:11 +08:00
|
|
|
/*
|
|
|
|
* linux/mm/page_isolation.c
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/mm.h>
|
|
|
|
#include <linux/page-isolation.h>
|
|
|
|
#include <linux/pageblock-flags.h>
|
2012-08-01 07:43:50 +08:00
|
|
|
#include <linux/memory.h>
|
2013-09-12 05:22:09 +08:00
|
|
|
#include <linux/hugetlb.h>
|
2016-07-27 06:23:43 +08:00
|
|
|
#include <linux/page_owner.h>
|
2017-07-11 06:48:47 +08:00
|
|
|
#include <linux/migrate.h>
|
2007-10-16 16:26:11 +08:00
|
|
|
#include "internal.h"
|
|
|
|
|
2016-01-15 07:18:42 +08:00
|
|
|
#define CREATE_TRACE_POINTS
|
|
|
|
#include <trace/events/page_isolation.h>
|
|
|
|
|
2022-05-13 11:22:57 +08:00
|
|
|
/*
|
2022-05-13 11:22:58 +08:00
|
|
|
* This function checks whether the range [start_pfn, end_pfn) includes
|
|
|
|
* unmovable pages or not. The range must fall into a single pageblock and
|
|
|
|
* consequently belong to a single zone.
|
2022-05-13 11:22:57 +08:00
|
|
|
*
|
|
|
|
* PageLRU check without isolation or lru_lock could race so that
|
|
|
|
* MIGRATE_MOVABLE block might include unmovable pages. And __PageMovable
|
|
|
|
* check without lock_page also may miss some movable non-lru pages at
|
|
|
|
* race condition. So you can't expect this function should be exact.
|
|
|
|
*
|
|
|
|
* Returns a page without holding a reference. If the caller wants to
|
|
|
|
* dereference that page (e.g., dumping), it has to make sure that it
|
|
|
|
* cannot get removed (e.g., via memory unplug) concurrently.
|
|
|
|
*
|
|
|
|
*/
|
2022-05-13 11:22:58 +08:00
|
|
|
static struct page *has_unmovable_pages(unsigned long start_pfn, unsigned long end_pfn,
|
|
|
|
int migratetype, int flags)
|
2022-05-13 11:22:57 +08:00
|
|
|
{
|
2022-05-13 11:22:58 +08:00
|
|
|
struct page *page = pfn_to_page(start_pfn);
|
|
|
|
struct zone *zone = page_zone(page);
|
|
|
|
unsigned long pfn;
|
|
|
|
|
2022-09-07 14:08:42 +08:00
|
|
|
VM_BUG_ON(pageblock_start_pfn(start_pfn) !=
|
|
|
|
pageblock_start_pfn(end_pfn - 1));
|
2022-05-13 11:22:57 +08:00
|
|
|
|
|
|
|
if (is_migrate_cma_page(page)) {
|
|
|
|
/*
|
|
|
|
* CMA allocations (alloc_contig_range) really need to mark
|
|
|
|
* isolate CMA pageblocks even when they are not movable in fact
|
|
|
|
* so consider them movable here.
|
|
|
|
*/
|
|
|
|
if (is_migrate_cma(migratetype))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return page;
|
|
|
|
}
|
|
|
|
|
2022-05-13 11:22:58 +08:00
|
|
|
for (pfn = start_pfn; pfn < end_pfn; pfn++) {
|
|
|
|
page = pfn_to_page(pfn);
|
2022-05-13 11:22:57 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Both, bootmem allocations and memory holes are marked
|
|
|
|
* PG_reserved and are unmovable. We can even have unmovable
|
|
|
|
* allocations inside ZONE_MOVABLE, for example when
|
|
|
|
* specifying "movablecore".
|
|
|
|
*/
|
|
|
|
if (PageReserved(page))
|
|
|
|
return page;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the zone is movable and we have ruled out all reserved
|
|
|
|
* pages then it should be reasonably safe to assume the rest
|
|
|
|
* is movable.
|
|
|
|
*/
|
|
|
|
if (zone_idx(zone) == ZONE_MOVABLE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Hugepages are not in LRU lists, but they're movable.
|
|
|
|
* THPs are on the LRU, but need to be counted as #small pages.
|
|
|
|
* We need not scan over tail pages because we don't
|
|
|
|
* handle each tail page individually in migration.
|
|
|
|
*/
|
|
|
|
if (PageHuge(page) || PageTransCompound(page)) {
|
|
|
|
struct page *head = compound_head(page);
|
|
|
|
unsigned int skip_pages;
|
|
|
|
|
|
|
|
if (PageHuge(page)) {
|
|
|
|
if (!hugepage_migration_supported(page_hstate(head)))
|
|
|
|
return page;
|
|
|
|
} else if (!PageLRU(head) && !__PageMovable(head)) {
|
|
|
|
return page;
|
|
|
|
}
|
|
|
|
|
|
|
|
skip_pages = compound_nr(head) - (page - head);
|
2022-05-13 11:22:58 +08:00
|
|
|
pfn += skip_pages - 1;
|
2022-05-13 11:22:57 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We can't use page_count without pin a page
|
|
|
|
* because another CPU can free compound page.
|
|
|
|
* This check already skips compound tails of THP
|
|
|
|
* because their page->_refcount is zero at all time.
|
|
|
|
*/
|
|
|
|
if (!page_ref_count(page)) {
|
|
|
|
if (PageBuddy(page))
|
2022-05-13 11:22:58 +08:00
|
|
|
pfn += (1 << buddy_order(page)) - 1;
|
2022-05-13 11:22:57 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The HWPoisoned page may be not in buddy system, and
|
|
|
|
* page_count() is not 0.
|
|
|
|
*/
|
|
|
|
if ((flags & MEMORY_OFFLINE) && PageHWPoison(page))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We treat all PageOffline() pages as movable when offlining
|
|
|
|
* to give drivers a chance to decrement their reference count
|
|
|
|
* in MEM_GOING_OFFLINE in order to indicate that these pages
|
|
|
|
* can be offlined as there are no direct references anymore.
|
|
|
|
* For actually unmovable PageOffline() where the driver does
|
|
|
|
* not support this, we will fail later when trying to actually
|
|
|
|
* move these pages that still have a reference count > 0.
|
|
|
|
* (false negatives in this function only)
|
|
|
|
*/
|
|
|
|
if ((flags & MEMORY_OFFLINE) && PageOffline(page))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (__PageMovable(page) || PageLRU(page))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If there are RECLAIMABLE pages, we need to check
|
|
|
|
* it. But now, memory offline itself doesn't call
|
|
|
|
* shrink_node_slabs() and it still to be fixed.
|
|
|
|
*/
|
|
|
|
return page;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2022-05-13 11:22:58 +08:00
|
|
|
/*
|
|
|
|
* This function set pageblock migratetype to isolate if no unmovable page is
|
|
|
|
* present in [start_pfn, end_pfn). The pageblock must intersect with
|
|
|
|
* [start_pfn, end_pfn).
|
|
|
|
*/
|
|
|
|
static int set_migratetype_isolate(struct page *page, int migratetype, int isol_flags,
|
|
|
|
unsigned long start_pfn, unsigned long end_pfn)
|
2012-08-01 07:43:50 +08:00
|
|
|
{
|
2020-10-14 07:55:28 +08:00
|
|
|
struct zone *zone = page_zone(page);
|
|
|
|
struct page *unmovable;
|
2020-01-31 14:14:01 +08:00
|
|
|
unsigned long flags;
|
2022-05-13 11:22:58 +08:00
|
|
|
unsigned long check_unmovable_start, check_unmovable_end;
|
2012-08-01 07:43:50 +08:00
|
|
|
|
|
|
|
spin_lock_irqsave(&zone->lock, flags);
|
|
|
|
|
2018-04-06 07:25:26 +08:00
|
|
|
/*
|
|
|
|
* We assume the caller intended to SET migrate type to isolate.
|
|
|
|
* If it is already set, then someone else must have raced and
|
2020-10-14 07:55:21 +08:00
|
|
|
* set it before us.
|
2018-04-06 07:25:26 +08:00
|
|
|
*/
|
2020-10-14 07:55:21 +08:00
|
|
|
if (is_migrate_isolate_page(page)) {
|
|
|
|
spin_unlock_irqrestore(&zone->lock, flags);
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
2018-04-06 07:25:26 +08:00
|
|
|
|
2012-08-01 07:43:50 +08:00
|
|
|
/*
|
|
|
|
* FIXME: Now, memory hotplug doesn't call shrink_slab() by itself.
|
|
|
|
* We just check MOVABLE pages.
|
2022-05-13 11:22:58 +08:00
|
|
|
*
|
|
|
|
* Pass the intersection of [start_pfn, end_pfn) and the page's pageblock
|
|
|
|
* to avoid redundant checks.
|
2012-08-01 07:43:50 +08:00
|
|
|
*/
|
2022-05-13 11:22:58 +08:00
|
|
|
check_unmovable_start = max(page_to_pfn(page), start_pfn);
|
2022-09-07 14:08:42 +08:00
|
|
|
check_unmovable_end = min(pageblock_end_pfn(page_to_pfn(page)),
|
2022-05-13 11:22:58 +08:00
|
|
|
end_pfn);
|
|
|
|
|
|
|
|
unmovable = has_unmovable_pages(check_unmovable_start, check_unmovable_end,
|
|
|
|
migratetype, isol_flags);
|
mm/hotplug: silence a lockdep splat with printk()
It is not that hard to trigger lockdep splats by calling printk from
under zone->lock. Most of them are false positives caused by lock
chains introduced early in the boot process and they do not cause any
real problems (although most of the early boot lock dependencies could
happen after boot as well). There are some console drivers which do
allocate from the printk context as well and those should be fixed. In
any case, false positives are not that trivial to workaround and it is
far from optimal to lose lockdep functionality for something that is a
non-issue.
So change has_unmovable_pages() so that it no longer calls dump_page()
itself - instead it returns a "struct page *" of the unmovable page back
to the caller so that in the case of a has_unmovable_pages() failure,
the caller can call dump_page() after releasing zone->lock. Also, make
dump_page() is able to report a CMA page as well, so the reason string
from has_unmovable_pages() can be removed.
Even though has_unmovable_pages doesn't hold any reference to the
returned page this should be reasonably safe for the purpose of
reporting the page (dump_page) because it cannot be hotremoved in the
context of memory unplug. The state of the page might change but that
is the case even with the existing code as zone->lock only plays role
for free pages.
While at it, remove a similar but unnecessary debug-only printk() as
well. A sample of one of those lockdep splats is,
WARNING: possible circular locking dependency detected
------------------------------------------------------
test.sh/8653 is trying to acquire lock:
ffffffff865a4460 (console_owner){-.-.}, at:
console_unlock+0x207/0x750
but task is already holding lock:
ffff88883fff3c58 (&(&zone->lock)->rlock){-.-.}, at:
__offline_isolated_pages+0x179/0x3e0
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #3 (&(&zone->lock)->rlock){-.-.}:
__lock_acquire+0x5b3/0xb40
lock_acquire+0x126/0x280
_raw_spin_lock+0x2f/0x40
rmqueue_bulk.constprop.21+0xb6/0x1160
get_page_from_freelist+0x898/0x22c0
__alloc_pages_nodemask+0x2f3/0x1cd0
alloc_pages_current+0x9c/0x110
allocate_slab+0x4c6/0x19c0
new_slab+0x46/0x70
___slab_alloc+0x58b/0x960
__slab_alloc+0x43/0x70
__kmalloc+0x3ad/0x4b0
__tty_buffer_request_room+0x100/0x250
tty_insert_flip_string_fixed_flag+0x67/0x110
pty_write+0xa2/0xf0
n_tty_write+0x36b/0x7b0
tty_write+0x284/0x4c0
__vfs_write+0x50/0xa0
vfs_write+0x105/0x290
redirected_tty_write+0x6a/0xc0
do_iter_write+0x248/0x2a0
vfs_writev+0x106/0x1e0
do_writev+0xd4/0x180
__x64_sys_writev+0x45/0x50
do_syscall_64+0xcc/0x76c
entry_SYSCALL_64_after_hwframe+0x49/0xbe
-> #2 (&(&port->lock)->rlock){-.-.}:
__lock_acquire+0x5b3/0xb40
lock_acquire+0x126/0x280
_raw_spin_lock_irqsave+0x3a/0x50
tty_port_tty_get+0x20/0x60
tty_port_default_wakeup+0xf/0x30
tty_port_tty_wakeup+0x39/0x40
uart_write_wakeup+0x2a/0x40
serial8250_tx_chars+0x22e/0x440
serial8250_handle_irq.part.8+0x14a/0x170
serial8250_default_handle_irq+0x5c/0x90
serial8250_interrupt+0xa6/0x130
__handle_irq_event_percpu+0x78/0x4f0
handle_irq_event_percpu+0x70/0x100
handle_irq_event+0x5a/0x8b
handle_edge_irq+0x117/0x370
do_IRQ+0x9e/0x1e0
ret_from_intr+0x0/0x2a
cpuidle_enter_state+0x156/0x8e0
cpuidle_enter+0x41/0x70
call_cpuidle+0x5e/0x90
do_idle+0x333/0x370
cpu_startup_entry+0x1d/0x1f
start_secondary+0x290/0x330
secondary_startup_64+0xb6/0xc0
-> #1 (&port_lock_key){-.-.}:
__lock_acquire+0x5b3/0xb40
lock_acquire+0x126/0x280
_raw_spin_lock_irqsave+0x3a/0x50
serial8250_console_write+0x3e4/0x450
univ8250_console_write+0x4b/0x60
console_unlock+0x501/0x750
vprintk_emit+0x10d/0x340
vprintk_default+0x1f/0x30
vprintk_func+0x44/0xd4
printk+0x9f/0xc5
-> #0 (console_owner){-.-.}:
check_prev_add+0x107/0xea0
validate_chain+0x8fc/0x1200
__lock_acquire+0x5b3/0xb40
lock_acquire+0x126/0x280
console_unlock+0x269/0x750
vprintk_emit+0x10d/0x340
vprintk_default+0x1f/0x30
vprintk_func+0x44/0xd4
printk+0x9f/0xc5
__offline_isolated_pages.cold.52+0x2f/0x30a
offline_isolated_pages_cb+0x17/0x30
walk_system_ram_range+0xda/0x160
__offline_pages+0x79c/0xa10
offline_pages+0x11/0x20
memory_subsys_offline+0x7e/0xc0
device_offline+0xd5/0x110
state_store+0xc6/0xe0
dev_attr_store+0x3f/0x60
sysfs_kf_write+0x89/0xb0
kernfs_fop_write+0x188/0x240
__vfs_write+0x50/0xa0
vfs_write+0x105/0x290
ksys_write+0xc6/0x160
__x64_sys_write+0x43/0x50
do_syscall_64+0xcc/0x76c
entry_SYSCALL_64_after_hwframe+0x49/0xbe
other info that might help us debug this:
Chain exists of:
console_owner --> &(&port->lock)->rlock --> &(&zone->lock)->rlock
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(&(&zone->lock)->rlock);
lock(&(&port->lock)->rlock);
lock(&(&zone->lock)->rlock);
lock(console_owner);
*** DEADLOCK ***
9 locks held by test.sh/8653:
#0: ffff88839ba7d408 (sb_writers#4){.+.+}, at:
vfs_write+0x25f/0x290
#1: ffff888277618880 (&of->mutex){+.+.}, at:
kernfs_fop_write+0x128/0x240
#2: ffff8898131fc218 (kn->count#115){.+.+}, at:
kernfs_fop_write+0x138/0x240
#3: ffffffff86962a80 (device_hotplug_lock){+.+.}, at:
lock_device_hotplug_sysfs+0x16/0x50
#4: ffff8884374f4990 (&dev->mutex){....}, at:
device_offline+0x70/0x110
#5: ffffffff86515250 (cpu_hotplug_lock.rw_sem){++++}, at:
__offline_pages+0xbf/0xa10
#6: ffffffff867405f0 (mem_hotplug_lock.rw_sem){++++}, at:
percpu_down_write+0x87/0x2f0
#7: ffff88883fff3c58 (&(&zone->lock)->rlock){-.-.}, at:
__offline_isolated_pages+0x179/0x3e0
#8: ffffffff865a4920 (console_lock){+.+.}, at:
vprintk_emit+0x100/0x340
stack backtrace:
Hardware name: HPE ProLiant DL560 Gen10/ProLiant DL560 Gen10,
BIOS U34 05/21/2019
Call Trace:
dump_stack+0x86/0xca
print_circular_bug.cold.31+0x243/0x26e
check_noncircular+0x29e/0x2e0
check_prev_add+0x107/0xea0
validate_chain+0x8fc/0x1200
__lock_acquire+0x5b3/0xb40
lock_acquire+0x126/0x280
console_unlock+0x269/0x750
vprintk_emit+0x10d/0x340
vprintk_default+0x1f/0x30
vprintk_func+0x44/0xd4
printk+0x9f/0xc5
__offline_isolated_pages.cold.52+0x2f/0x30a
offline_isolated_pages_cb+0x17/0x30
walk_system_ram_range+0xda/0x160
__offline_pages+0x79c/0xa10
offline_pages+0x11/0x20
memory_subsys_offline+0x7e/0xc0
device_offline+0xd5/0x110
state_store+0xc6/0xe0
dev_attr_store+0x3f/0x60
sysfs_kf_write+0x89/0xb0
kernfs_fop_write+0x188/0x240
__vfs_write+0x50/0xa0
vfs_write+0x105/0x290
ksys_write+0xc6/0x160
__x64_sys_write+0x43/0x50
do_syscall_64+0xcc/0x76c
entry_SYSCALL_64_after_hwframe+0x49/0xbe
Link: http://lkml.kernel.org/r/20200117181200.20299-1-cai@lca.pw
Signed-off-by: Qian Cai <cai@lca.pw>
Reviewed-by: David Hildenbrand <david@redhat.com>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
Cc: Petr Mladek <pmladek@suse.com>
Cc: Steven Rostedt (VMware) <rostedt@goodmis.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-01-31 14:14:57 +08:00
|
|
|
if (!unmovable) {
|
2012-10-09 07:32:00 +08:00
|
|
|
unsigned long nr_pages;
|
2017-11-16 09:33:26 +08:00
|
|
|
int mt = get_pageblock_migratetype(page);
|
2012-10-09 07:32:00 +08:00
|
|
|
|
2013-01-05 07:35:08 +08:00
|
|
|
set_pageblock_migratetype(page, MIGRATE_ISOLATE);
|
mm/page_alloc: fix incorrect isolation behavior by rechecking migratetype
Before describing bugs itself, I first explain definition of freepage.
1. pages on buddy list are counted as freepage.
2. pages on isolate migratetype buddy list are *not* counted as freepage.
3. pages on cma buddy list are counted as CMA freepage, too.
Now, I describe problems and related patch.
Patch 1: There is race conditions on getting pageblock migratetype that
it results in misplacement of freepages on buddy list, incorrect
freepage count and un-availability of freepage.
Patch 2: Freepages on pcp list could have stale cached information to
determine migratetype of buddy list to go. This causes misplacement of
freepages on buddy list and incorrect freepage count.
Patch 4: Merging between freepages on different migratetype of
pageblocks will cause freepages accouting problem. This patch fixes it.
Without patchset [3], above problem doesn't happens on my CMA allocation
test, because CMA reserved pages aren't used at all. So there is no
chance for above race.
With patchset [3], I did simple CMA allocation test and get below
result:
- Virtual machine, 4 cpus, 1024 MB memory, 256 MB CMA reservation
- run kernel build (make -j16) on background
- 30 times CMA allocation(8MB * 30 = 240MB) attempts in 5 sec interval
- Result: more than 5000 freepage count are missed
With patchset [3] and this patchset, I found that no freepage count are
missed so that I conclude that problems are solved.
On my simple memory offlining test, these problems also occur on that
environment, too.
This patch (of 4):
There are two paths to reach core free function of buddy allocator,
__free_one_page(), one is free_one_page()->__free_one_page() and the
other is free_hot_cold_page()->free_pcppages_bulk()->__free_one_page().
Each paths has race condition causing serious problems. At first, this
patch is focused on first type of freepath. And then, following patch
will solve the problem in second type of freepath.
In the first type of freepath, we got migratetype of freeing page
without holding the zone lock, so it could be racy. There are two cases
of this race.
1. pages are added to isolate buddy list after restoring orignal
migratetype
CPU1 CPU2
get migratetype => return MIGRATE_ISOLATE
call free_one_page() with MIGRATE_ISOLATE
grab the zone lock
unisolate pageblock
release the zone lock
grab the zone lock
call __free_one_page() with MIGRATE_ISOLATE
freepage go into isolate buddy list,
although pageblock is already unisolated
This may cause two problems. One is that we can't use this page anymore
until next isolation attempt of this pageblock, because freepage is on
isolate buddy list. The other is that freepage accouting could be wrong
due to merging between different buddy list. Freepages on isolate buddy
list aren't counted as freepage, but ones on normal buddy list are
counted as freepage. If merge happens, buddy freepage on normal buddy
list is inevitably moved to isolate buddy list without any consideration
of freepage accouting so it could be incorrect.
2. pages are added to normal buddy list while pageblock is isolated.
It is similar with above case.
This also may cause two problems. One is that we can't keep these
freepages from being allocated. Although this pageblock is isolated,
freepage would be added to normal buddy list so that it could be
allocated without any restriction. And the other problem is same as
case 1, that it, incorrect freepage accouting.
This race condition would be prevented by checking migratetype again
with holding the zone lock. Because it is somewhat heavy operation and
it isn't needed in common case, we want to avoid rechecking as much as
possible. So this patch introduce new variable, nr_isolate_pageblock in
struct zone to check if there is isolated pageblock. With this, we can
avoid to re-check migratetype in common case and do it only if there is
isolated pageblock or migratetype is MIGRATE_ISOLATE. This solve above
mentioned problems.
Changes from v3:
Add one more check in free_one_page() that checks whether migratetype is
MIGRATE_ISOLATE or not. Without this, abovementioned case 1 could happens.
Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Acked-by: Minchan Kim <minchan@kernel.org>
Acked-by: Michal Nazarewicz <mina86@mina86.com>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Cc: "Kirill A. Shutemov" <kirill@shutemov.name>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
Cc: Zhang Yanfei <zhangyanfei@cn.fujitsu.com>
Cc: Tang Chen <tangchen@cn.fujitsu.com>
Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Cc: Wen Congyang <wency@cn.fujitsu.com>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Cc: Laura Abbott <lauraa@codeaurora.org>
Cc: Heesub Shin <heesub.shin@samsung.com>
Cc: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
Cc: Ritesh Harjani <ritesh.list@gmail.com>
Cc: Gioh Kim <gioh.kim@lge.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2014-11-14 07:19:11 +08:00
|
|
|
zone->nr_isolate_pageblock++;
|
mm, page_alloc: count movable pages when stealing from pageblock
When stealing pages from pageblock of a different migratetype, we count
how many free pages were stolen, and change the pageblock's migratetype
if more than half of the pageblock was free. This might be too
conservative, as there might be other pages that are not free, but were
allocated with the same migratetype as our allocation requested.
While we cannot determine the migratetype of allocated pages precisely
(at least without the page_owner functionality enabled), we can count
pages that compaction would try to isolate for migration - those are
either on LRU or __PageMovable(). The rest can be assumed to be
MIGRATE_RECLAIMABLE or MIGRATE_UNMOVABLE, which we cannot easily
distinguish. This counting can be done as part of free page stealing
with little additional overhead.
The page stealing code is changed so that it considers free pages plus
pages of the "good" migratetype for the decision whether to change
pageblock's migratetype.
The result should be more accurate migratetype of pageblocks wrt the
actual pages in the pageblocks, when stealing from semi-occupied
pageblocks. This should help the efficiency of page grouping by
mobility.
In testing based on 4.9 kernel with stress-highalloc from mmtests
configured for order-4 GFP_KERNEL allocations, this patch has reduced
the number of unmovable allocations falling back to movable pageblocks
by 47%. The number of movable allocations falling back to other
pageblocks are increased by 55%, but these events don't cause permanent
fragmentation, so the tradeoff should be positive. Later patches also
offset the movable fallback increase to some extent.
[akpm@linux-foundation.org: merge fix]
Link: http://lkml.kernel.org/r/20170307131545.28577-5-vbabka@suse.cz
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
Acked-by: Mel Gorman <mgorman@techsingularity.net>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: David Rientjes <rientjes@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2017-05-09 06:54:40 +08:00
|
|
|
nr_pages = move_freepages_block(zone, page, MIGRATE_ISOLATE,
|
|
|
|
NULL);
|
2012-10-09 07:32:00 +08:00
|
|
|
|
2017-11-16 09:33:26 +08:00
|
|
|
__mod_zone_freepage_state(zone, -nr_pages, mt);
|
2020-10-14 07:55:28 +08:00
|
|
|
spin_unlock_irqrestore(&zone->lock, flags);
|
|
|
|
return 0;
|
2012-08-01 07:43:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
spin_unlock_irqrestore(&zone->lock, flags);
|
2020-10-14 07:55:28 +08:00
|
|
|
if (isol_flags & REPORT_FAILURE) {
|
2020-10-14 07:55:24 +08:00
|
|
|
/*
|
|
|
|
* printk() with zone->lock held will likely trigger a
|
|
|
|
* lockdep splat, so defer it here.
|
|
|
|
*/
|
|
|
|
dump_page(unmovable, "unmovable page");
|
2020-01-31 14:15:01 +08:00
|
|
|
}
|
mm/hotplug: silence a lockdep splat with printk()
It is not that hard to trigger lockdep splats by calling printk from
under zone->lock. Most of them are false positives caused by lock
chains introduced early in the boot process and they do not cause any
real problems (although most of the early boot lock dependencies could
happen after boot as well). There are some console drivers which do
allocate from the printk context as well and those should be fixed. In
any case, false positives are not that trivial to workaround and it is
far from optimal to lose lockdep functionality for something that is a
non-issue.
So change has_unmovable_pages() so that it no longer calls dump_page()
itself - instead it returns a "struct page *" of the unmovable page back
to the caller so that in the case of a has_unmovable_pages() failure,
the caller can call dump_page() after releasing zone->lock. Also, make
dump_page() is able to report a CMA page as well, so the reason string
from has_unmovable_pages() can be removed.
Even though has_unmovable_pages doesn't hold any reference to the
returned page this should be reasonably safe for the purpose of
reporting the page (dump_page) because it cannot be hotremoved in the
context of memory unplug. The state of the page might change but that
is the case even with the existing code as zone->lock only plays role
for free pages.
While at it, remove a similar but unnecessary debug-only printk() as
well. A sample of one of those lockdep splats is,
WARNING: possible circular locking dependency detected
------------------------------------------------------
test.sh/8653 is trying to acquire lock:
ffffffff865a4460 (console_owner){-.-.}, at:
console_unlock+0x207/0x750
but task is already holding lock:
ffff88883fff3c58 (&(&zone->lock)->rlock){-.-.}, at:
__offline_isolated_pages+0x179/0x3e0
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #3 (&(&zone->lock)->rlock){-.-.}:
__lock_acquire+0x5b3/0xb40
lock_acquire+0x126/0x280
_raw_spin_lock+0x2f/0x40
rmqueue_bulk.constprop.21+0xb6/0x1160
get_page_from_freelist+0x898/0x22c0
__alloc_pages_nodemask+0x2f3/0x1cd0
alloc_pages_current+0x9c/0x110
allocate_slab+0x4c6/0x19c0
new_slab+0x46/0x70
___slab_alloc+0x58b/0x960
__slab_alloc+0x43/0x70
__kmalloc+0x3ad/0x4b0
__tty_buffer_request_room+0x100/0x250
tty_insert_flip_string_fixed_flag+0x67/0x110
pty_write+0xa2/0xf0
n_tty_write+0x36b/0x7b0
tty_write+0x284/0x4c0
__vfs_write+0x50/0xa0
vfs_write+0x105/0x290
redirected_tty_write+0x6a/0xc0
do_iter_write+0x248/0x2a0
vfs_writev+0x106/0x1e0
do_writev+0xd4/0x180
__x64_sys_writev+0x45/0x50
do_syscall_64+0xcc/0x76c
entry_SYSCALL_64_after_hwframe+0x49/0xbe
-> #2 (&(&port->lock)->rlock){-.-.}:
__lock_acquire+0x5b3/0xb40
lock_acquire+0x126/0x280
_raw_spin_lock_irqsave+0x3a/0x50
tty_port_tty_get+0x20/0x60
tty_port_default_wakeup+0xf/0x30
tty_port_tty_wakeup+0x39/0x40
uart_write_wakeup+0x2a/0x40
serial8250_tx_chars+0x22e/0x440
serial8250_handle_irq.part.8+0x14a/0x170
serial8250_default_handle_irq+0x5c/0x90
serial8250_interrupt+0xa6/0x130
__handle_irq_event_percpu+0x78/0x4f0
handle_irq_event_percpu+0x70/0x100
handle_irq_event+0x5a/0x8b
handle_edge_irq+0x117/0x370
do_IRQ+0x9e/0x1e0
ret_from_intr+0x0/0x2a
cpuidle_enter_state+0x156/0x8e0
cpuidle_enter+0x41/0x70
call_cpuidle+0x5e/0x90
do_idle+0x333/0x370
cpu_startup_entry+0x1d/0x1f
start_secondary+0x290/0x330
secondary_startup_64+0xb6/0xc0
-> #1 (&port_lock_key){-.-.}:
__lock_acquire+0x5b3/0xb40
lock_acquire+0x126/0x280
_raw_spin_lock_irqsave+0x3a/0x50
serial8250_console_write+0x3e4/0x450
univ8250_console_write+0x4b/0x60
console_unlock+0x501/0x750
vprintk_emit+0x10d/0x340
vprintk_default+0x1f/0x30
vprintk_func+0x44/0xd4
printk+0x9f/0xc5
-> #0 (console_owner){-.-.}:
check_prev_add+0x107/0xea0
validate_chain+0x8fc/0x1200
__lock_acquire+0x5b3/0xb40
lock_acquire+0x126/0x280
console_unlock+0x269/0x750
vprintk_emit+0x10d/0x340
vprintk_default+0x1f/0x30
vprintk_func+0x44/0xd4
printk+0x9f/0xc5
__offline_isolated_pages.cold.52+0x2f/0x30a
offline_isolated_pages_cb+0x17/0x30
walk_system_ram_range+0xda/0x160
__offline_pages+0x79c/0xa10
offline_pages+0x11/0x20
memory_subsys_offline+0x7e/0xc0
device_offline+0xd5/0x110
state_store+0xc6/0xe0
dev_attr_store+0x3f/0x60
sysfs_kf_write+0x89/0xb0
kernfs_fop_write+0x188/0x240
__vfs_write+0x50/0xa0
vfs_write+0x105/0x290
ksys_write+0xc6/0x160
__x64_sys_write+0x43/0x50
do_syscall_64+0xcc/0x76c
entry_SYSCALL_64_after_hwframe+0x49/0xbe
other info that might help us debug this:
Chain exists of:
console_owner --> &(&port->lock)->rlock --> &(&zone->lock)->rlock
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(&(&zone->lock)->rlock);
lock(&(&port->lock)->rlock);
lock(&(&zone->lock)->rlock);
lock(console_owner);
*** DEADLOCK ***
9 locks held by test.sh/8653:
#0: ffff88839ba7d408 (sb_writers#4){.+.+}, at:
vfs_write+0x25f/0x290
#1: ffff888277618880 (&of->mutex){+.+.}, at:
kernfs_fop_write+0x128/0x240
#2: ffff8898131fc218 (kn->count#115){.+.+}, at:
kernfs_fop_write+0x138/0x240
#3: ffffffff86962a80 (device_hotplug_lock){+.+.}, at:
lock_device_hotplug_sysfs+0x16/0x50
#4: ffff8884374f4990 (&dev->mutex){....}, at:
device_offline+0x70/0x110
#5: ffffffff86515250 (cpu_hotplug_lock.rw_sem){++++}, at:
__offline_pages+0xbf/0xa10
#6: ffffffff867405f0 (mem_hotplug_lock.rw_sem){++++}, at:
percpu_down_write+0x87/0x2f0
#7: ffff88883fff3c58 (&(&zone->lock)->rlock){-.-.}, at:
__offline_isolated_pages+0x179/0x3e0
#8: ffffffff865a4920 (console_lock){+.+.}, at:
vprintk_emit+0x100/0x340
stack backtrace:
Hardware name: HPE ProLiant DL560 Gen10/ProLiant DL560 Gen10,
BIOS U34 05/21/2019
Call Trace:
dump_stack+0x86/0xca
print_circular_bug.cold.31+0x243/0x26e
check_noncircular+0x29e/0x2e0
check_prev_add+0x107/0xea0
validate_chain+0x8fc/0x1200
__lock_acquire+0x5b3/0xb40
lock_acquire+0x126/0x280
console_unlock+0x269/0x750
vprintk_emit+0x10d/0x340
vprintk_default+0x1f/0x30
vprintk_func+0x44/0xd4
printk+0x9f/0xc5
__offline_isolated_pages.cold.52+0x2f/0x30a
offline_isolated_pages_cb+0x17/0x30
walk_system_ram_range+0xda/0x160
__offline_pages+0x79c/0xa10
offline_pages+0x11/0x20
memory_subsys_offline+0x7e/0xc0
device_offline+0xd5/0x110
state_store+0xc6/0xe0
dev_attr_store+0x3f/0x60
sysfs_kf_write+0x89/0xb0
kernfs_fop_write+0x188/0x240
__vfs_write+0x50/0xa0
vfs_write+0x105/0x290
ksys_write+0xc6/0x160
__x64_sys_write+0x43/0x50
do_syscall_64+0xcc/0x76c
entry_SYSCALL_64_after_hwframe+0x49/0xbe
Link: http://lkml.kernel.org/r/20200117181200.20299-1-cai@lca.pw
Signed-off-by: Qian Cai <cai@lca.pw>
Reviewed-by: David Hildenbrand <david@redhat.com>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
Cc: Petr Mladek <pmladek@suse.com>
Cc: Steven Rostedt (VMware) <rostedt@goodmis.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-01-31 14:14:57 +08:00
|
|
|
|
2020-10-14 07:55:28 +08:00
|
|
|
return -EBUSY;
|
2012-08-01 07:43:50 +08:00
|
|
|
}
|
|
|
|
|
2022-05-13 11:22:58 +08:00
|
|
|
static void unset_migratetype_isolate(struct page *page, int migratetype)
|
2012-08-01 07:43:50 +08:00
|
|
|
{
|
|
|
|
struct zone *zone;
|
2012-10-09 07:32:00 +08:00
|
|
|
unsigned long flags, nr_pages;
|
2016-07-27 06:24:01 +08:00
|
|
|
bool isolated_page = false;
|
2014-11-14 07:19:21 +08:00
|
|
|
unsigned int order;
|
|
|
|
struct page *buddy;
|
2012-10-09 07:32:00 +08:00
|
|
|
|
2012-08-01 07:43:50 +08:00
|
|
|
zone = page_zone(page);
|
|
|
|
spin_lock_irqsave(&zone->lock, flags);
|
2017-05-04 05:52:55 +08:00
|
|
|
if (!is_migrate_isolate_page(page))
|
2012-08-01 07:43:50 +08:00
|
|
|
goto out;
|
2014-11-14 07:19:21 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Because freepage with more than pageblock_order on isolated
|
|
|
|
* pageblock is restricted to merge due to freepage counting problem,
|
|
|
|
* it is possible that there is free buddy page.
|
|
|
|
* move_freepages_block() doesn't care of merge so we need other
|
|
|
|
* approach in order to merge them. Isolation and free will make
|
|
|
|
* these pages to be merged.
|
|
|
|
*/
|
|
|
|
if (PageBuddy(page)) {
|
2020-10-16 11:10:15 +08:00
|
|
|
order = buddy_order(page);
|
2023-03-15 19:31:33 +08:00
|
|
|
if (order >= pageblock_order && order < MAX_ORDER) {
|
2022-04-29 14:16:01 +08:00
|
|
|
buddy = find_buddy_page_pfn(page, page_to_pfn(page),
|
|
|
|
order, NULL);
|
|
|
|
if (buddy && !is_migrate_isolate_page(buddy)) {
|
2021-11-06 04:42:19 +08:00
|
|
|
isolated_page = !!__isolate_free_page(page, order);
|
|
|
|
/*
|
|
|
|
* Isolating a free page in an isolated pageblock
|
|
|
|
* is expected to always work as watermarks don't
|
|
|
|
* apply here.
|
|
|
|
*/
|
|
|
|
VM_WARN_ON(!isolated_page);
|
2014-11-14 07:19:21 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we isolate freepage with more than pageblock_order, there
|
|
|
|
* should be no freepage in the range, so we could avoid costly
|
|
|
|
* pageblock scanning for freepage moving.
|
mm/page_alloc: move pages to tail in move_to_free_list()
Whenever we move pages between freelists via move_to_free_list()/
move_freepages_block(), we don't actually touch the pages:
1. Page isolation doesn't actually touch the pages, it simply isolates
pageblocks and moves all free pages to the MIGRATE_ISOLATE freelist.
When undoing isolation, we move the pages back to the target list.
2. Page stealing (steal_suitable_fallback()) moves free pages directly
between lists without touching them.
3. reserve_highatomic_pageblock()/unreserve_highatomic_pageblock() moves
free pages directly between freelists without touching them.
We already place pages to the tail of the freelists when undoing isolation
via __putback_isolated_page(), let's do it in any case (e.g., if order <=
pageblock_order) and document the behavior. To simplify, let's move the
pages to the tail for all move_to_free_list()/move_freepages_block() users.
In 2., the target list is empty, so there should be no change. In 3., we
might observe a change, however, highatomic is more concerned about
allocations succeeding than cache hotness - if we ever realize this change
degrades a workload, we can special-case this instance and add a proper
comment.
This change results in all pages getting onlined via online_pages() to be
placed to the tail of the freelist.
Signed-off-by: David Hildenbrand <david@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Oscar Salvador <osalvador@suse.de>
Reviewed-by: Wei Yang <richard.weiyang@linux.alibaba.com>
Acked-by: Pankaj Gupta <pankaj.gupta.linux@gmail.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Cc: Alexander Duyck <alexander.h.duyck@linux.intel.com>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Scott Cheloha <cheloha@linux.ibm.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Haiyang Zhang <haiyangz@microsoft.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Stephen Hemminger <sthemmin@microsoft.com>
Cc: Wei Liu <wei.liu@kernel.org>
Link: https://lkml.kernel.org/r/20201005121534.15649-4-david@redhat.com
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-10-16 11:09:30 +08:00
|
|
|
*
|
|
|
|
* We didn't actually touch any of the isolated pages, so place them
|
|
|
|
* to the tail of the freelist. This is an optimization for memory
|
|
|
|
* onlining - just onlined memory won't immediately be considered for
|
|
|
|
* allocation.
|
2014-11-14 07:19:21 +08:00
|
|
|
*/
|
2022-02-04 12:49:06 +08:00
|
|
|
if (!isolated_page) {
|
mm, page_alloc: count movable pages when stealing from pageblock
When stealing pages from pageblock of a different migratetype, we count
how many free pages were stolen, and change the pageblock's migratetype
if more than half of the pageblock was free. This might be too
conservative, as there might be other pages that are not free, but were
allocated with the same migratetype as our allocation requested.
While we cannot determine the migratetype of allocated pages precisely
(at least without the page_owner functionality enabled), we can count
pages that compaction would try to isolate for migration - those are
either on LRU or __PageMovable(). The rest can be assumed to be
MIGRATE_RECLAIMABLE or MIGRATE_UNMOVABLE, which we cannot easily
distinguish. This counting can be done as part of free page stealing
with little additional overhead.
The page stealing code is changed so that it considers free pages plus
pages of the "good" migratetype for the decision whether to change
pageblock's migratetype.
The result should be more accurate migratetype of pageblocks wrt the
actual pages in the pageblocks, when stealing from semi-occupied
pageblocks. This should help the efficiency of page grouping by
mobility.
In testing based on 4.9 kernel with stress-highalloc from mmtests
configured for order-4 GFP_KERNEL allocations, this patch has reduced
the number of unmovable allocations falling back to movable pageblocks
by 47%. The number of movable allocations falling back to other
pageblocks are increased by 55%, but these events don't cause permanent
fragmentation, so the tradeoff should be positive. Later patches also
offset the movable fallback increase to some extent.
[akpm@linux-foundation.org: merge fix]
Link: http://lkml.kernel.org/r/20170307131545.28577-5-vbabka@suse.cz
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
Acked-by: Mel Gorman <mgorman@techsingularity.net>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: David Rientjes <rientjes@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2017-05-09 06:54:40 +08:00
|
|
|
nr_pages = move_freepages_block(zone, page, migratetype, NULL);
|
2014-11-14 07:19:21 +08:00
|
|
|
__mod_zone_freepage_state(zone, nr_pages, migratetype);
|
|
|
|
}
|
2013-01-05 07:35:08 +08:00
|
|
|
set_pageblock_migratetype(page, migratetype);
|
2020-04-07 11:04:53 +08:00
|
|
|
if (isolated_page)
|
|
|
|
__putback_isolated_page(page, order, migratetype);
|
mm/page_alloc: fix incorrect isolation behavior by rechecking migratetype
Before describing bugs itself, I first explain definition of freepage.
1. pages on buddy list are counted as freepage.
2. pages on isolate migratetype buddy list are *not* counted as freepage.
3. pages on cma buddy list are counted as CMA freepage, too.
Now, I describe problems and related patch.
Patch 1: There is race conditions on getting pageblock migratetype that
it results in misplacement of freepages on buddy list, incorrect
freepage count and un-availability of freepage.
Patch 2: Freepages on pcp list could have stale cached information to
determine migratetype of buddy list to go. This causes misplacement of
freepages on buddy list and incorrect freepage count.
Patch 4: Merging between freepages on different migratetype of
pageblocks will cause freepages accouting problem. This patch fixes it.
Without patchset [3], above problem doesn't happens on my CMA allocation
test, because CMA reserved pages aren't used at all. So there is no
chance for above race.
With patchset [3], I did simple CMA allocation test and get below
result:
- Virtual machine, 4 cpus, 1024 MB memory, 256 MB CMA reservation
- run kernel build (make -j16) on background
- 30 times CMA allocation(8MB * 30 = 240MB) attempts in 5 sec interval
- Result: more than 5000 freepage count are missed
With patchset [3] and this patchset, I found that no freepage count are
missed so that I conclude that problems are solved.
On my simple memory offlining test, these problems also occur on that
environment, too.
This patch (of 4):
There are two paths to reach core free function of buddy allocator,
__free_one_page(), one is free_one_page()->__free_one_page() and the
other is free_hot_cold_page()->free_pcppages_bulk()->__free_one_page().
Each paths has race condition causing serious problems. At first, this
patch is focused on first type of freepath. And then, following patch
will solve the problem in second type of freepath.
In the first type of freepath, we got migratetype of freeing page
without holding the zone lock, so it could be racy. There are two cases
of this race.
1. pages are added to isolate buddy list after restoring orignal
migratetype
CPU1 CPU2
get migratetype => return MIGRATE_ISOLATE
call free_one_page() with MIGRATE_ISOLATE
grab the zone lock
unisolate pageblock
release the zone lock
grab the zone lock
call __free_one_page() with MIGRATE_ISOLATE
freepage go into isolate buddy list,
although pageblock is already unisolated
This may cause two problems. One is that we can't use this page anymore
until next isolation attempt of this pageblock, because freepage is on
isolate buddy list. The other is that freepage accouting could be wrong
due to merging between different buddy list. Freepages on isolate buddy
list aren't counted as freepage, but ones on normal buddy list are
counted as freepage. If merge happens, buddy freepage on normal buddy
list is inevitably moved to isolate buddy list without any consideration
of freepage accouting so it could be incorrect.
2. pages are added to normal buddy list while pageblock is isolated.
It is similar with above case.
This also may cause two problems. One is that we can't keep these
freepages from being allocated. Although this pageblock is isolated,
freepage would be added to normal buddy list so that it could be
allocated without any restriction. And the other problem is same as
case 1, that it, incorrect freepage accouting.
This race condition would be prevented by checking migratetype again
with holding the zone lock. Because it is somewhat heavy operation and
it isn't needed in common case, we want to avoid rechecking as much as
possible. So this patch introduce new variable, nr_isolate_pageblock in
struct zone to check if there is isolated pageblock. With this, we can
avoid to re-check migratetype in common case and do it only if there is
isolated pageblock or migratetype is MIGRATE_ISOLATE. This solve above
mentioned problems.
Changes from v3:
Add one more check in free_one_page() that checks whether migratetype is
MIGRATE_ISOLATE or not. Without this, abovementioned case 1 could happens.
Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Acked-by: Minchan Kim <minchan@kernel.org>
Acked-by: Michal Nazarewicz <mina86@mina86.com>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Cc: "Kirill A. Shutemov" <kirill@shutemov.name>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
Cc: Zhang Yanfei <zhangyanfei@cn.fujitsu.com>
Cc: Tang Chen <tangchen@cn.fujitsu.com>
Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Cc: Wen Congyang <wency@cn.fujitsu.com>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Cc: Laura Abbott <lauraa@codeaurora.org>
Cc: Heesub Shin <heesub.shin@samsung.com>
Cc: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
Cc: Ritesh Harjani <ritesh.list@gmail.com>
Cc: Gioh Kim <gioh.kim@lge.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2014-11-14 07:19:11 +08:00
|
|
|
zone->nr_isolate_pageblock--;
|
2012-08-01 07:43:50 +08:00
|
|
|
out:
|
|
|
|
spin_unlock_irqrestore(&zone->lock, flags);
|
|
|
|
}
|
|
|
|
|
2007-10-16 16:26:11 +08:00
|
|
|
static inline struct page *
|
|
|
|
__first_valid_page(unsigned long pfn, unsigned long nr_pages)
|
|
|
|
{
|
|
|
|
int i;
|
2017-07-07 06:38:04 +08:00
|
|
|
|
|
|
|
for (i = 0; i < nr_pages; i++) {
|
|
|
|
struct page *page;
|
|
|
|
|
|
|
|
page = pfn_to_online_page(pfn + i);
|
|
|
|
if (!page)
|
|
|
|
continue;
|
|
|
|
return page;
|
|
|
|
}
|
|
|
|
return NULL;
|
2007-10-16 16:26:11 +08:00
|
|
|
}
|
|
|
|
|
2022-05-13 11:22:58 +08:00
|
|
|
/**
|
|
|
|
* isolate_single_pageblock() -- tries to isolate a pageblock that might be
|
|
|
|
* within a free or in-use page.
|
|
|
|
* @boundary_pfn: pageblock-aligned pfn that a page might cross
|
mm: fix a potential infinite loop in start_isolate_page_range()
In isolate_single_pageblock() called by start_isolate_page_range(), there
are some pageblock isolation issues causing a potential infinite loop when
isolating a page range. This is reported by Qian Cai.
1. the pageblock was isolated by just changing pageblock migratetype
without checking unmovable pages. Calling set_migratetype_isolate() to
isolate pageblock properly.
2. an off-by-one error caused migrating pages unnecessarily, since the page
is not crossing pageblock boundary.
3. migrating a compound page across pageblock boundary then splitting the
free page later has a small race window that the free page might be
allocated again, so that the code will try again, causing an potential
infinite loop. Temporarily set the to-be-migrated page's pageblock to
MIGRATE_ISOLATE to prevent that and bail out early if no free page is
found after page migration.
An additional fix to split_free_page() aims to avoid crashing in
__free_one_page(). When the free page is split at the specified
split_pfn_offset, free_page_order should check both the first bit of
free_page_pfn and the last bit of split_pfn_offset and use the smaller
one. For example, if free_page_pfn=0x10000, split_pfn_offset=0xc000,
free_page_order should first be 0x8000 then 0x4000, instead of 0x4000 then
0x8000, which the original algorithm did.
[akpm@linux-foundation.org: suppress min() warning]
Link: https://lkml.kernel.org/r/20220524194756.1698351-1-zi.yan@sent.com
Fixes: b2c9e2fbba3253 ("mm: make alloc_contig_range work at pageblock granularity")
Signed-off-by: Zi Yan <ziy@nvidia.com>
Reported-by: Qian Cai <quic_qiancai@quicinc.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: David Hildenbrand <david@redhat.com>
Cc: Eric Ren <renzhengeek@gmail.com>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Mike Rapoport <rppt@linux.ibm.com>
Cc: Minchan Kim <minchan@kernel.org>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2022-05-25 03:47:56 +08:00
|
|
|
* @flags: isolation flags
|
2022-05-13 11:22:58 +08:00
|
|
|
* @gfp_flags: GFP flags used for migrating pages
|
|
|
|
* @isolate_before: isolate the pageblock before the boundary_pfn
|
2022-06-02 14:21:16 +08:00
|
|
|
* @skip_isolation: the flag to skip the pageblock isolation in second
|
|
|
|
* isolate_single_pageblock()
|
2022-09-14 10:39:13 +08:00
|
|
|
* @migratetype: migrate type to set in error recovery.
|
2022-05-13 11:22:58 +08:00
|
|
|
*
|
2023-03-15 19:31:33 +08:00
|
|
|
* Free and in-use pages can be as big as MAX_ORDER and contain more than one
|
2022-05-13 11:22:58 +08:00
|
|
|
* pageblock. When not all pageblocks within a page are isolated at the same
|
|
|
|
* time, free page accounting can go wrong. For example, in the case of
|
2023-03-15 19:31:33 +08:00
|
|
|
* MAX_ORDER = pageblock_order + 1, a MAX_ORDER page has two pagelbocks.
|
|
|
|
* [ MAX_ORDER ]
|
2022-05-13 11:22:58 +08:00
|
|
|
* [ pageblock0 | pageblock1 ]
|
|
|
|
* When either pageblock is isolated, if it is a free page, the page is not
|
|
|
|
* split into separate migratetype lists, which is supposed to; if it is an
|
|
|
|
* in-use page and freed later, __free_one_page() does not split the free page
|
|
|
|
* either. The function handles this by splitting the free page or migrating
|
|
|
|
* the in-use page then splitting the free page.
|
|
|
|
*/
|
mm: fix a potential infinite loop in start_isolate_page_range()
In isolate_single_pageblock() called by start_isolate_page_range(), there
are some pageblock isolation issues causing a potential infinite loop when
isolating a page range. This is reported by Qian Cai.
1. the pageblock was isolated by just changing pageblock migratetype
without checking unmovable pages. Calling set_migratetype_isolate() to
isolate pageblock properly.
2. an off-by-one error caused migrating pages unnecessarily, since the page
is not crossing pageblock boundary.
3. migrating a compound page across pageblock boundary then splitting the
free page later has a small race window that the free page might be
allocated again, so that the code will try again, causing an potential
infinite loop. Temporarily set the to-be-migrated page's pageblock to
MIGRATE_ISOLATE to prevent that and bail out early if no free page is
found after page migration.
An additional fix to split_free_page() aims to avoid crashing in
__free_one_page(). When the free page is split at the specified
split_pfn_offset, free_page_order should check both the first bit of
free_page_pfn and the last bit of split_pfn_offset and use the smaller
one. For example, if free_page_pfn=0x10000, split_pfn_offset=0xc000,
free_page_order should first be 0x8000 then 0x4000, instead of 0x4000 then
0x8000, which the original algorithm did.
[akpm@linux-foundation.org: suppress min() warning]
Link: https://lkml.kernel.org/r/20220524194756.1698351-1-zi.yan@sent.com
Fixes: b2c9e2fbba3253 ("mm: make alloc_contig_range work at pageblock granularity")
Signed-off-by: Zi Yan <ziy@nvidia.com>
Reported-by: Qian Cai <quic_qiancai@quicinc.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: David Hildenbrand <david@redhat.com>
Cc: Eric Ren <renzhengeek@gmail.com>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Mike Rapoport <rppt@linux.ibm.com>
Cc: Minchan Kim <minchan@kernel.org>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2022-05-25 03:47:56 +08:00
|
|
|
static int isolate_single_pageblock(unsigned long boundary_pfn, int flags,
|
2022-09-14 10:39:13 +08:00
|
|
|
gfp_t gfp_flags, bool isolate_before, bool skip_isolation,
|
|
|
|
int migratetype)
|
2022-05-13 11:22:58 +08:00
|
|
|
{
|
|
|
|
unsigned long start_pfn;
|
|
|
|
unsigned long isolate_pageblock;
|
|
|
|
unsigned long pfn;
|
|
|
|
struct zone *zone;
|
mm: fix a potential infinite loop in start_isolate_page_range()
In isolate_single_pageblock() called by start_isolate_page_range(), there
are some pageblock isolation issues causing a potential infinite loop when
isolating a page range. This is reported by Qian Cai.
1. the pageblock was isolated by just changing pageblock migratetype
without checking unmovable pages. Calling set_migratetype_isolate() to
isolate pageblock properly.
2. an off-by-one error caused migrating pages unnecessarily, since the page
is not crossing pageblock boundary.
3. migrating a compound page across pageblock boundary then splitting the
free page later has a small race window that the free page might be
allocated again, so that the code will try again, causing an potential
infinite loop. Temporarily set the to-be-migrated page's pageblock to
MIGRATE_ISOLATE to prevent that and bail out early if no free page is
found after page migration.
An additional fix to split_free_page() aims to avoid crashing in
__free_one_page(). When the free page is split at the specified
split_pfn_offset, free_page_order should check both the first bit of
free_page_pfn and the last bit of split_pfn_offset and use the smaller
one. For example, if free_page_pfn=0x10000, split_pfn_offset=0xc000,
free_page_order should first be 0x8000 then 0x4000, instead of 0x4000 then
0x8000, which the original algorithm did.
[akpm@linux-foundation.org: suppress min() warning]
Link: https://lkml.kernel.org/r/20220524194756.1698351-1-zi.yan@sent.com
Fixes: b2c9e2fbba3253 ("mm: make alloc_contig_range work at pageblock granularity")
Signed-off-by: Zi Yan <ziy@nvidia.com>
Reported-by: Qian Cai <quic_qiancai@quicinc.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: David Hildenbrand <david@redhat.com>
Cc: Eric Ren <renzhengeek@gmail.com>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Mike Rapoport <rppt@linux.ibm.com>
Cc: Minchan Kim <minchan@kernel.org>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2022-05-25 03:47:56 +08:00
|
|
|
int ret;
|
2022-05-13 11:22:58 +08:00
|
|
|
|
2022-09-07 14:08:44 +08:00
|
|
|
VM_BUG_ON(!pageblock_aligned(boundary_pfn));
|
2022-05-13 11:22:58 +08:00
|
|
|
|
|
|
|
if (isolate_before)
|
|
|
|
isolate_pageblock = boundary_pfn - pageblock_nr_pages;
|
|
|
|
else
|
|
|
|
isolate_pageblock = boundary_pfn;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* scan at the beginning of MAX_ORDER_NR_PAGES aligned range to avoid
|
|
|
|
* only isolating a subset of pageblocks from a bigger than pageblock
|
|
|
|
* free or in-use page. Also make sure all to-be-isolated pageblocks
|
|
|
|
* are within the same zone.
|
|
|
|
*/
|
|
|
|
zone = page_zone(pfn_to_page(isolate_pageblock));
|
|
|
|
start_pfn = max(ALIGN_DOWN(isolate_pageblock, MAX_ORDER_NR_PAGES),
|
|
|
|
zone->zone_start_pfn);
|
|
|
|
|
2022-09-14 10:39:13 +08:00
|
|
|
if (skip_isolation) {
|
2022-10-21 18:15:55 +08:00
|
|
|
int mt __maybe_unused = get_pageblock_migratetype(pfn_to_page(isolate_pageblock));
|
mm: fix a potential infinite loop in start_isolate_page_range()
In isolate_single_pageblock() called by start_isolate_page_range(), there
are some pageblock isolation issues causing a potential infinite loop when
isolating a page range. This is reported by Qian Cai.
1. the pageblock was isolated by just changing pageblock migratetype
without checking unmovable pages. Calling set_migratetype_isolate() to
isolate pageblock properly.
2. an off-by-one error caused migrating pages unnecessarily, since the page
is not crossing pageblock boundary.
3. migrating a compound page across pageblock boundary then splitting the
free page later has a small race window that the free page might be
allocated again, so that the code will try again, causing an potential
infinite loop. Temporarily set the to-be-migrated page's pageblock to
MIGRATE_ISOLATE to prevent that and bail out early if no free page is
found after page migration.
An additional fix to split_free_page() aims to avoid crashing in
__free_one_page(). When the free page is split at the specified
split_pfn_offset, free_page_order should check both the first bit of
free_page_pfn and the last bit of split_pfn_offset and use the smaller
one. For example, if free_page_pfn=0x10000, split_pfn_offset=0xc000,
free_page_order should first be 0x8000 then 0x4000, instead of 0x4000 then
0x8000, which the original algorithm did.
[akpm@linux-foundation.org: suppress min() warning]
Link: https://lkml.kernel.org/r/20220524194756.1698351-1-zi.yan@sent.com
Fixes: b2c9e2fbba3253 ("mm: make alloc_contig_range work at pageblock granularity")
Signed-off-by: Zi Yan <ziy@nvidia.com>
Reported-by: Qian Cai <quic_qiancai@quicinc.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: David Hildenbrand <david@redhat.com>
Cc: Eric Ren <renzhengeek@gmail.com>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Mike Rapoport <rppt@linux.ibm.com>
Cc: Minchan Kim <minchan@kernel.org>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2022-05-25 03:47:56 +08:00
|
|
|
|
2022-09-14 10:39:13 +08:00
|
|
|
VM_BUG_ON(!is_migrate_isolate(mt));
|
|
|
|
} else {
|
|
|
|
ret = set_migratetype_isolate(pfn_to_page(isolate_pageblock), migratetype,
|
|
|
|
flags, isolate_pageblock, isolate_pageblock + pageblock_nr_pages);
|
2022-05-27 07:15:30 +08:00
|
|
|
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
2022-05-13 11:22:58 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Bail out early when the to-be-isolated pageblock does not form
|
|
|
|
* a free or in-use page across boundary_pfn:
|
|
|
|
*
|
|
|
|
* 1. isolate before boundary_pfn: the page after is not online
|
|
|
|
* 2. isolate after boundary_pfn: the page before is not online
|
|
|
|
*
|
|
|
|
* This also ensures correctness. Without it, when isolate after
|
|
|
|
* boundary_pfn and [start_pfn, boundary_pfn) are not online,
|
|
|
|
* __first_valid_page() will return unexpected NULL in the for loop
|
|
|
|
* below.
|
|
|
|
*/
|
|
|
|
if (isolate_before) {
|
|
|
|
if (!pfn_to_online_page(boundary_pfn))
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
if (!pfn_to_online_page(boundary_pfn - 1))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (pfn = start_pfn; pfn < boundary_pfn;) {
|
|
|
|
struct page *page = __first_valid_page(pfn, boundary_pfn - pfn);
|
|
|
|
|
|
|
|
VM_BUG_ON(!page);
|
|
|
|
pfn = page_to_pfn(page);
|
|
|
|
/*
|
|
|
|
* start_pfn is MAX_ORDER_NR_PAGES aligned, if there is any
|
|
|
|
* free pages in [start_pfn, boundary_pfn), its head page will
|
|
|
|
* always be in the range.
|
|
|
|
*/
|
|
|
|
if (PageBuddy(page)) {
|
|
|
|
int order = buddy_order(page);
|
|
|
|
|
2022-05-27 07:15:31 +08:00
|
|
|
if (pfn + (1UL << order) > boundary_pfn) {
|
|
|
|
/* free page changed before split, check it again */
|
|
|
|
if (split_free_page(page, order, boundary_pfn - pfn))
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
pfn += 1UL << order;
|
2022-05-13 11:22:58 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* migrate compound pages then let the free page handling code
|
|
|
|
* above do the rest. If migration is not possible, just fail.
|
|
|
|
*/
|
|
|
|
if (PageCompound(page)) {
|
|
|
|
struct page *head = compound_head(page);
|
|
|
|
unsigned long head_pfn = page_to_pfn(head);
|
2022-05-31 10:44:50 +08:00
|
|
|
unsigned long nr_pages = compound_nr(head);
|
2022-05-13 11:22:58 +08:00
|
|
|
|
mm: fix a potential infinite loop in start_isolate_page_range()
In isolate_single_pageblock() called by start_isolate_page_range(), there
are some pageblock isolation issues causing a potential infinite loop when
isolating a page range. This is reported by Qian Cai.
1. the pageblock was isolated by just changing pageblock migratetype
without checking unmovable pages. Calling set_migratetype_isolate() to
isolate pageblock properly.
2. an off-by-one error caused migrating pages unnecessarily, since the page
is not crossing pageblock boundary.
3. migrating a compound page across pageblock boundary then splitting the
free page later has a small race window that the free page might be
allocated again, so that the code will try again, causing an potential
infinite loop. Temporarily set the to-be-migrated page's pageblock to
MIGRATE_ISOLATE to prevent that and bail out early if no free page is
found after page migration.
An additional fix to split_free_page() aims to avoid crashing in
__free_one_page(). When the free page is split at the specified
split_pfn_offset, free_page_order should check both the first bit of
free_page_pfn and the last bit of split_pfn_offset and use the smaller
one. For example, if free_page_pfn=0x10000, split_pfn_offset=0xc000,
free_page_order should first be 0x8000 then 0x4000, instead of 0x4000 then
0x8000, which the original algorithm did.
[akpm@linux-foundation.org: suppress min() warning]
Link: https://lkml.kernel.org/r/20220524194756.1698351-1-zi.yan@sent.com
Fixes: b2c9e2fbba3253 ("mm: make alloc_contig_range work at pageblock granularity")
Signed-off-by: Zi Yan <ziy@nvidia.com>
Reported-by: Qian Cai <quic_qiancai@quicinc.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: David Hildenbrand <david@redhat.com>
Cc: Eric Ren <renzhengeek@gmail.com>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Mike Rapoport <rppt@linux.ibm.com>
Cc: Minchan Kim <minchan@kernel.org>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2022-05-25 03:47:56 +08:00
|
|
|
if (head_pfn + nr_pages <= boundary_pfn) {
|
2022-05-13 11:22:58 +08:00
|
|
|
pfn = head_pfn + nr_pages;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#if defined CONFIG_COMPACTION || defined CONFIG_CMA
|
|
|
|
/*
|
|
|
|
* hugetlb, lru compound (THP), and movable compound pages
|
|
|
|
* can be migrated. Otherwise, fail the isolation.
|
|
|
|
*/
|
|
|
|
if (PageHuge(page) || PageLRU(page) || __PageMovable(page)) {
|
|
|
|
int order;
|
|
|
|
unsigned long outer_pfn;
|
mm: fix a potential infinite loop in start_isolate_page_range()
In isolate_single_pageblock() called by start_isolate_page_range(), there
are some pageblock isolation issues causing a potential infinite loop when
isolating a page range. This is reported by Qian Cai.
1. the pageblock was isolated by just changing pageblock migratetype
without checking unmovable pages. Calling set_migratetype_isolate() to
isolate pageblock properly.
2. an off-by-one error caused migrating pages unnecessarily, since the page
is not crossing pageblock boundary.
3. migrating a compound page across pageblock boundary then splitting the
free page later has a small race window that the free page might be
allocated again, so that the code will try again, causing an potential
infinite loop. Temporarily set the to-be-migrated page's pageblock to
MIGRATE_ISOLATE to prevent that and bail out early if no free page is
found after page migration.
An additional fix to split_free_page() aims to avoid crashing in
__free_one_page(). When the free page is split at the specified
split_pfn_offset, free_page_order should check both the first bit of
free_page_pfn and the last bit of split_pfn_offset and use the smaller
one. For example, if free_page_pfn=0x10000, split_pfn_offset=0xc000,
free_page_order should first be 0x8000 then 0x4000, instead of 0x4000 then
0x8000, which the original algorithm did.
[akpm@linux-foundation.org: suppress min() warning]
Link: https://lkml.kernel.org/r/20220524194756.1698351-1-zi.yan@sent.com
Fixes: b2c9e2fbba3253 ("mm: make alloc_contig_range work at pageblock granularity")
Signed-off-by: Zi Yan <ziy@nvidia.com>
Reported-by: Qian Cai <quic_qiancai@quicinc.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: David Hildenbrand <david@redhat.com>
Cc: Eric Ren <renzhengeek@gmail.com>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Mike Rapoport <rppt@linux.ibm.com>
Cc: Minchan Kim <minchan@kernel.org>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2022-05-25 03:47:56 +08:00
|
|
|
int page_mt = get_pageblock_migratetype(page);
|
|
|
|
bool isolate_page = !is_migrate_isolate_page(page);
|
2022-05-13 11:22:58 +08:00
|
|
|
struct compact_control cc = {
|
|
|
|
.nr_migratepages = 0,
|
|
|
|
.order = -1,
|
|
|
|
.zone = page_zone(pfn_to_page(head_pfn)),
|
|
|
|
.mode = MIGRATE_SYNC,
|
|
|
|
.ignore_skip_hint = true,
|
|
|
|
.no_set_skip_hint = true,
|
|
|
|
.gfp_mask = gfp_flags,
|
|
|
|
.alloc_contig = true,
|
|
|
|
};
|
|
|
|
INIT_LIST_HEAD(&cc.migratepages);
|
|
|
|
|
mm: fix a potential infinite loop in start_isolate_page_range()
In isolate_single_pageblock() called by start_isolate_page_range(), there
are some pageblock isolation issues causing a potential infinite loop when
isolating a page range. This is reported by Qian Cai.
1. the pageblock was isolated by just changing pageblock migratetype
without checking unmovable pages. Calling set_migratetype_isolate() to
isolate pageblock properly.
2. an off-by-one error caused migrating pages unnecessarily, since the page
is not crossing pageblock boundary.
3. migrating a compound page across pageblock boundary then splitting the
free page later has a small race window that the free page might be
allocated again, so that the code will try again, causing an potential
infinite loop. Temporarily set the to-be-migrated page's pageblock to
MIGRATE_ISOLATE to prevent that and bail out early if no free page is
found after page migration.
An additional fix to split_free_page() aims to avoid crashing in
__free_one_page(). When the free page is split at the specified
split_pfn_offset, free_page_order should check both the first bit of
free_page_pfn and the last bit of split_pfn_offset and use the smaller
one. For example, if free_page_pfn=0x10000, split_pfn_offset=0xc000,
free_page_order should first be 0x8000 then 0x4000, instead of 0x4000 then
0x8000, which the original algorithm did.
[akpm@linux-foundation.org: suppress min() warning]
Link: https://lkml.kernel.org/r/20220524194756.1698351-1-zi.yan@sent.com
Fixes: b2c9e2fbba3253 ("mm: make alloc_contig_range work at pageblock granularity")
Signed-off-by: Zi Yan <ziy@nvidia.com>
Reported-by: Qian Cai <quic_qiancai@quicinc.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: David Hildenbrand <david@redhat.com>
Cc: Eric Ren <renzhengeek@gmail.com>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Mike Rapoport <rppt@linux.ibm.com>
Cc: Minchan Kim <minchan@kernel.org>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2022-05-25 03:47:56 +08:00
|
|
|
/*
|
|
|
|
* XXX: mark the page as MIGRATE_ISOLATE so that
|
|
|
|
* no one else can grab the freed page after migration.
|
|
|
|
* Ideally, the page should be freed as two separate
|
|
|
|
* pages to be added into separate migratetype free
|
|
|
|
* lists.
|
|
|
|
*/
|
|
|
|
if (isolate_page) {
|
|
|
|
ret = set_migratetype_isolate(page, page_mt,
|
|
|
|
flags, head_pfn, head_pfn + nr_pages);
|
|
|
|
if (ret)
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
|
2022-05-13 11:22:58 +08:00
|
|
|
ret = __alloc_contig_migrate_range(&cc, head_pfn,
|
|
|
|
head_pfn + nr_pages);
|
|
|
|
|
mm: fix a potential infinite loop in start_isolate_page_range()
In isolate_single_pageblock() called by start_isolate_page_range(), there
are some pageblock isolation issues causing a potential infinite loop when
isolating a page range. This is reported by Qian Cai.
1. the pageblock was isolated by just changing pageblock migratetype
without checking unmovable pages. Calling set_migratetype_isolate() to
isolate pageblock properly.
2. an off-by-one error caused migrating pages unnecessarily, since the page
is not crossing pageblock boundary.
3. migrating a compound page across pageblock boundary then splitting the
free page later has a small race window that the free page might be
allocated again, so that the code will try again, causing an potential
infinite loop. Temporarily set the to-be-migrated page's pageblock to
MIGRATE_ISOLATE to prevent that and bail out early if no free page is
found after page migration.
An additional fix to split_free_page() aims to avoid crashing in
__free_one_page(). When the free page is split at the specified
split_pfn_offset, free_page_order should check both the first bit of
free_page_pfn and the last bit of split_pfn_offset and use the smaller
one. For example, if free_page_pfn=0x10000, split_pfn_offset=0xc000,
free_page_order should first be 0x8000 then 0x4000, instead of 0x4000 then
0x8000, which the original algorithm did.
[akpm@linux-foundation.org: suppress min() warning]
Link: https://lkml.kernel.org/r/20220524194756.1698351-1-zi.yan@sent.com
Fixes: b2c9e2fbba3253 ("mm: make alloc_contig_range work at pageblock granularity")
Signed-off-by: Zi Yan <ziy@nvidia.com>
Reported-by: Qian Cai <quic_qiancai@quicinc.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: David Hildenbrand <david@redhat.com>
Cc: Eric Ren <renzhengeek@gmail.com>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Mike Rapoport <rppt@linux.ibm.com>
Cc: Minchan Kim <minchan@kernel.org>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2022-05-25 03:47:56 +08:00
|
|
|
/*
|
|
|
|
* restore the page's migratetype so that it can
|
|
|
|
* be split into separate migratetype free lists
|
|
|
|
* later.
|
|
|
|
*/
|
|
|
|
if (isolate_page)
|
|
|
|
unset_migratetype_isolate(page, page_mt);
|
|
|
|
|
2022-05-13 11:22:58 +08:00
|
|
|
if (ret)
|
|
|
|
goto failed;
|
|
|
|
/*
|
|
|
|
* reset pfn to the head of the free page, so
|
|
|
|
* that the free page handling code above can split
|
|
|
|
* the free page to the right migratetype list.
|
|
|
|
*
|
|
|
|
* head_pfn is not used here as a hugetlb page order
|
2023-03-15 19:31:33 +08:00
|
|
|
* can be bigger than MAX_ORDER, but after it is
|
2022-05-13 11:22:58 +08:00
|
|
|
* freed, the free page order is not. Use pfn within
|
|
|
|
* the range to find the head of the free page.
|
|
|
|
*/
|
|
|
|
order = 0;
|
|
|
|
outer_pfn = pfn;
|
|
|
|
while (!PageBuddy(pfn_to_page(outer_pfn))) {
|
mm: fix a potential infinite loop in start_isolate_page_range()
In isolate_single_pageblock() called by start_isolate_page_range(), there
are some pageblock isolation issues causing a potential infinite loop when
isolating a page range. This is reported by Qian Cai.
1. the pageblock was isolated by just changing pageblock migratetype
without checking unmovable pages. Calling set_migratetype_isolate() to
isolate pageblock properly.
2. an off-by-one error caused migrating pages unnecessarily, since the page
is not crossing pageblock boundary.
3. migrating a compound page across pageblock boundary then splitting the
free page later has a small race window that the free page might be
allocated again, so that the code will try again, causing an potential
infinite loop. Temporarily set the to-be-migrated page's pageblock to
MIGRATE_ISOLATE to prevent that and bail out early if no free page is
found after page migration.
An additional fix to split_free_page() aims to avoid crashing in
__free_one_page(). When the free page is split at the specified
split_pfn_offset, free_page_order should check both the first bit of
free_page_pfn and the last bit of split_pfn_offset and use the smaller
one. For example, if free_page_pfn=0x10000, split_pfn_offset=0xc000,
free_page_order should first be 0x8000 then 0x4000, instead of 0x4000 then
0x8000, which the original algorithm did.
[akpm@linux-foundation.org: suppress min() warning]
Link: https://lkml.kernel.org/r/20220524194756.1698351-1-zi.yan@sent.com
Fixes: b2c9e2fbba3253 ("mm: make alloc_contig_range work at pageblock granularity")
Signed-off-by: Zi Yan <ziy@nvidia.com>
Reported-by: Qian Cai <quic_qiancai@quicinc.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: David Hildenbrand <david@redhat.com>
Cc: Eric Ren <renzhengeek@gmail.com>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Mike Rapoport <rppt@linux.ibm.com>
Cc: Minchan Kim <minchan@kernel.org>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2022-05-25 03:47:56 +08:00
|
|
|
/* stop if we cannot find the free page */
|
2023-03-15 19:31:33 +08:00
|
|
|
if (++order > MAX_ORDER)
|
mm: fix a potential infinite loop in start_isolate_page_range()
In isolate_single_pageblock() called by start_isolate_page_range(), there
are some pageblock isolation issues causing a potential infinite loop when
isolating a page range. This is reported by Qian Cai.
1. the pageblock was isolated by just changing pageblock migratetype
without checking unmovable pages. Calling set_migratetype_isolate() to
isolate pageblock properly.
2. an off-by-one error caused migrating pages unnecessarily, since the page
is not crossing pageblock boundary.
3. migrating a compound page across pageblock boundary then splitting the
free page later has a small race window that the free page might be
allocated again, so that the code will try again, causing an potential
infinite loop. Temporarily set the to-be-migrated page's pageblock to
MIGRATE_ISOLATE to prevent that and bail out early if no free page is
found after page migration.
An additional fix to split_free_page() aims to avoid crashing in
__free_one_page(). When the free page is split at the specified
split_pfn_offset, free_page_order should check both the first bit of
free_page_pfn and the last bit of split_pfn_offset and use the smaller
one. For example, if free_page_pfn=0x10000, split_pfn_offset=0xc000,
free_page_order should first be 0x8000 then 0x4000, instead of 0x4000 then
0x8000, which the original algorithm did.
[akpm@linux-foundation.org: suppress min() warning]
Link: https://lkml.kernel.org/r/20220524194756.1698351-1-zi.yan@sent.com
Fixes: b2c9e2fbba3253 ("mm: make alloc_contig_range work at pageblock granularity")
Signed-off-by: Zi Yan <ziy@nvidia.com>
Reported-by: Qian Cai <quic_qiancai@quicinc.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: David Hildenbrand <david@redhat.com>
Cc: Eric Ren <renzhengeek@gmail.com>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Mike Rapoport <rppt@linux.ibm.com>
Cc: Minchan Kim <minchan@kernel.org>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2022-05-25 03:47:56 +08:00
|
|
|
goto failed;
|
2022-05-13 11:22:58 +08:00
|
|
|
outer_pfn &= ~0UL << order;
|
|
|
|
}
|
|
|
|
pfn = outer_pfn;
|
|
|
|
continue;
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
|
|
|
|
pfn++;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
failed:
|
|
|
|
/* restore the original migratetype */
|
2022-05-27 07:15:30 +08:00
|
|
|
if (!skip_isolation)
|
2022-09-14 10:39:13 +08:00
|
|
|
unset_migratetype_isolate(pfn_to_page(isolate_pageblock), migratetype);
|
2022-05-13 11:22:58 +08:00
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
2019-03-29 11:43:34 +08:00
|
|
|
/**
|
|
|
|
* start_isolate_page_range() - make page-allocation-type of range of pages to
|
|
|
|
* be MIGRATE_ISOLATE.
|
|
|
|
* @start_pfn: The lower PFN of the range to be isolated.
|
|
|
|
* @end_pfn: The upper PFN of the range to be isolated.
|
|
|
|
* @migratetype: Migrate type to set in error recovery.
|
|
|
|
* @flags: The following flags are allowed (they can be combined in
|
|
|
|
* a bit mask)
|
2019-12-01 09:54:07 +08:00
|
|
|
* MEMORY_OFFLINE - isolate to offline (!allocate) memory
|
|
|
|
* e.g., skip over PageHWPoison() pages
|
mm: Allow to offline unmovable PageOffline() pages via MEM_GOING_OFFLINE
virtio-mem wants to allow to offline memory blocks of which some parts
were unplugged (allocated via alloc_contig_range()), especially, to later
offline and remove completely unplugged memory blocks. The important part
is that PageOffline() has to remain set until the section is offline, so
these pages will never get accessed (e.g., when dumping). The pages should
not be handed back to the buddy (which would require clearing PageOffline()
and result in issues if offlining fails and the pages are suddenly in the
buddy).
Let's allow to do that by allowing to isolate any PageOffline() page
when offlining. This way, we can reach the memory hotplug notifier
MEM_GOING_OFFLINE, where the driver can signal that he is fine with
offlining this page by dropping its reference count. PageOffline() pages
with a reference count of 0 can then be skipped when offlining the
pages (like if they were free, however they are not in the buddy).
Anybody who uses PageOffline() pages and does not agree to offline them
(e.g., Hyper-V balloon, XEN balloon, VMWare balloon for 2MB pages) will not
decrement the reference count and make offlining fail when trying to
migrate such an unmovable page. So there should be no observable change.
Same applies to balloon compaction users (movable PageOffline() pages), the
pages will simply be migrated.
Note 1: If offlining fails, a driver has to increment the reference
count again in MEM_CANCEL_OFFLINE.
Note 2: A driver that makes use of this has to be aware that re-onlining
the memory block has to be handled by hooking into onlining code
(online_page_callback_t), resetting the page PageOffline() and
not giving them to the buddy.
Reviewed-by: Alexander Duyck <alexander.h.duyck@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Tested-by: Pankaj Gupta <pankaj.gupta.linux@gmail.com>
Acked-by: Andrew Morton <akpm@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Juergen Gross <jgross@suse.com>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: Pavel Tatashin <pavel.tatashin@microsoft.com>
Cc: Alexander Duyck <alexander.h.duyck@linux.intel.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Anthony Yznaga <anthony.yznaga@oracle.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Mike Rapoport <rppt@linux.ibm.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Anshuman Khandual <anshuman.khandual@arm.com>
Cc: Qian Cai <cai@lca.pw>
Cc: Pingfan Liu <kernelfans@gmail.com>
Signed-off-by: David Hildenbrand <david@redhat.com>
Link: https://lore.kernel.org/r/20200507140139.17083-7-david@redhat.com
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2020-05-07 22:01:30 +08:00
|
|
|
* and PageOffline() pages.
|
2019-03-29 11:43:34 +08:00
|
|
|
* REPORT_FAILURE - report details about the failure to
|
|
|
|
* isolate the range
|
2022-05-13 11:22:58 +08:00
|
|
|
* @gfp_flags: GFP flags used for migrating pages that sit across the
|
|
|
|
* range boundaries.
|
2007-10-16 16:26:11 +08:00
|
|
|
*
|
|
|
|
* Making page-allocation-type to be MIGRATE_ISOLATE means free pages in
|
|
|
|
* the range will never be allocated. Any free pages and pages freed in the
|
2019-03-29 11:43:34 +08:00
|
|
|
* future will not be allocated again. If specified range includes migrate types
|
|
|
|
* other than MOVABLE or CMA, this will fail with -EBUSY. For isolating all
|
|
|
|
* pages in the range finally, the caller have to free all pages in the range.
|
|
|
|
* test_page_isolated() can be used for test it.
|
2018-04-06 07:25:26 +08:00
|
|
|
*
|
2022-05-13 11:22:58 +08:00
|
|
|
* The function first tries to isolate the pageblocks at the beginning and end
|
|
|
|
* of the range, since there might be pages across the range boundaries.
|
|
|
|
* Afterwards, it isolates the rest of the range.
|
|
|
|
*
|
2018-04-06 07:25:26 +08:00
|
|
|
* There is no high level synchronization mechanism that prevents two threads
|
2019-03-29 11:43:34 +08:00
|
|
|
* from trying to isolate overlapping ranges. If this happens, one thread
|
2018-04-06 07:25:26 +08:00
|
|
|
* will notice pageblocks in the overlapping range already set to isolate.
|
|
|
|
* This happens in set_migratetype_isolate, and set_migratetype_isolate
|
2019-03-29 11:43:34 +08:00
|
|
|
* returns an error. We then clean up by restoring the migration type on
|
|
|
|
* pageblocks we may have modified and return -EBUSY to caller. This
|
2018-04-06 07:25:26 +08:00
|
|
|
* prevents two threads from simultaneously working on overlapping ranges.
|
2019-03-29 11:43:34 +08:00
|
|
|
*
|
2020-09-19 12:20:31 +08:00
|
|
|
* Please note that there is no strong synchronization with the page allocator
|
|
|
|
* either. Pages might be freed while their page blocks are marked ISOLATED.
|
2020-12-15 11:10:56 +08:00
|
|
|
* A call to drain_all_pages() after isolation can flush most of them. However
|
|
|
|
* in some cases pages might still end up on pcp lists and that would allow
|
2020-09-19 12:20:31 +08:00
|
|
|
* for their allocation even when they are in fact isolated already. Depending
|
mm, page_alloc: disable pcplists during memory offline
Memory offlining relies on page isolation to guarantee a forward progress
because pages cannot be reused while they are isolated. But the page
isolation itself doesn't prevent from races while freed pages are stored
on pcp lists and thus can be reused. This can be worked around by
repeated draining of pcplists, as done by commit 968318261221
("mm/memory_hotplug: drain per-cpu pages again during memory offline").
David and Michal would prefer that this race was closed in a way that
callers of page isolation who need stronger guarantees don't need to
repeatedly drain. David suggested disabling pcplists usage completely
during page isolation, instead of repeatedly draining them.
To achieve this without adding special cases in alloc/free fastpath, we
can use the same approach as boot pagesets - when pcp->high is 0, any
pcplist addition will be immediately flushed.
The race can thus be closed by setting pcp->high to 0 and draining
pcplists once, before calling start_isolate_page_range(). The draining
will serialize after processes that already disabled interrupts and read
the old value of pcp->high in free_unref_page_commit(), and processes that
have not yet disabled interrupts, will observe pcp->high == 0 when they
are rescheduled, and skip pcplists. This guarantees no stray pages on
pcplists in zones where isolation happens.
This patch thus adds zone_pcp_disable() and zone_pcp_enable() functions
that page isolation users can call before start_isolate_page_range() and
after unisolating (or offlining) the isolated pages.
Also, drain_all_pages() is optimized to only execute on cpus where
pcplists are not empty. The check can however race with a free to pcplist
that has not yet increased the pcp->count from 0 to 1. Thus make the
drain optionally skip the racy check and drain on all cpus, and use this
option in zone_pcp_disable().
As we have to avoid external updates to high and batch while pcplists are
disabled, we take pcp_batch_high_lock in zone_pcp_disable() and release it
in zone_pcp_enable(). This also synchronizes multiple users of
zone_pcp_disable()/enable().
Currently the only user of this functionality is offline_pages().
[vbabka@suse.cz: add comment, per David]
Link: https://lkml.kernel.org/r/527480ef-ed72-e1c1-52a0-1c5b0113df45@suse.cz
Link: https://lkml.kernel.org/r/20201111092812.11329-8-vbabka@suse.cz
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
Suggested-by: David Hildenbrand <david@redhat.com>
Suggested-by: Michal Hocko <mhocko@suse.com>
Reviewed-by: Oscar Salvador <osalvador@suse.de>
Reviewed-by: David Hildenbrand <david@redhat.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-12-15 11:10:59 +08:00
|
|
|
* on how strong of a guarantee the caller needs, zone_pcp_disable/enable()
|
|
|
|
* might be used to flush and disable pcplist before isolation and enable after
|
|
|
|
* unisolation.
|
2020-09-19 12:20:31 +08:00
|
|
|
*
|
2020-10-16 11:08:07 +08:00
|
|
|
* Return: 0 on success and -EBUSY if any part of range cannot be isolated.
|
2007-10-16 16:26:11 +08:00
|
|
|
*/
|
2012-04-03 21:06:15 +08:00
|
|
|
int start_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
|
2022-05-13 11:22:58 +08:00
|
|
|
int migratetype, int flags, gfp_t gfp_flags)
|
2007-10-16 16:26:11 +08:00
|
|
|
{
|
|
|
|
unsigned long pfn;
|
|
|
|
struct page *page;
|
2022-05-13 11:22:58 +08:00
|
|
|
/* isolation is done at page block granularity */
|
2022-09-07 14:08:42 +08:00
|
|
|
unsigned long isolate_start = pageblock_start_pfn(start_pfn);
|
2022-09-07 14:08:43 +08:00
|
|
|
unsigned long isolate_end = pageblock_align(end_pfn);
|
2022-05-13 11:22:58 +08:00
|
|
|
int ret;
|
2022-05-27 07:15:30 +08:00
|
|
|
bool skip_isolation = false;
|
2007-10-16 16:26:11 +08:00
|
|
|
|
2022-05-13 11:22:58 +08:00
|
|
|
/* isolate [isolate_start, isolate_start + pageblock_nr_pages) pageblock */
|
2022-09-14 10:39:13 +08:00
|
|
|
ret = isolate_single_pageblock(isolate_start, flags, gfp_flags, false,
|
|
|
|
skip_isolation, migratetype);
|
2022-05-13 11:22:58 +08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2022-05-27 07:15:30 +08:00
|
|
|
if (isolate_start == isolate_end - pageblock_nr_pages)
|
|
|
|
skip_isolation = true;
|
|
|
|
|
2022-05-13 11:22:58 +08:00
|
|
|
/* isolate [isolate_end - pageblock_nr_pages, isolate_end) pageblock */
|
2022-09-14 10:39:13 +08:00
|
|
|
ret = isolate_single_pageblock(isolate_end, flags, gfp_flags, true,
|
|
|
|
skip_isolation, migratetype);
|
2022-05-13 11:22:58 +08:00
|
|
|
if (ret) {
|
2022-05-13 11:22:58 +08:00
|
|
|
unset_migratetype_isolate(pfn_to_page(isolate_start), migratetype);
|
2022-05-13 11:22:58 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* skip isolated pageblocks at the beginning and end */
|
2022-05-13 11:22:58 +08:00
|
|
|
for (pfn = isolate_start + pageblock_nr_pages;
|
|
|
|
pfn < isolate_end - pageblock_nr_pages;
|
2007-10-16 16:26:11 +08:00
|
|
|
pfn += pageblock_nr_pages) {
|
|
|
|
page = __first_valid_page(pfn, pageblock_nr_pages);
|
2022-05-13 11:22:58 +08:00
|
|
|
if (page && set_migratetype_isolate(page, migratetype, flags,
|
|
|
|
start_pfn, end_pfn)) {
|
2022-05-13 11:22:58 +08:00
|
|
|
undo_isolate_page_range(isolate_start, pfn, migratetype);
|
2022-05-13 11:22:58 +08:00
|
|
|
unset_migratetype_isolate(
|
2022-05-13 11:22:58 +08:00
|
|
|
pfn_to_page(isolate_end - pageblock_nr_pages),
|
2022-05-13 11:22:58 +08:00
|
|
|
migratetype);
|
2021-11-06 04:42:16 +08:00
|
|
|
return -EBUSY;
|
2007-10-16 16:26:11 +08:00
|
|
|
}
|
|
|
|
}
|
2020-10-16 11:08:07 +08:00
|
|
|
return 0;
|
2007-10-16 16:26:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make isolated pages available again.
|
|
|
|
*/
|
2019-07-12 11:54:49 +08:00
|
|
|
void undo_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
|
2022-05-13 11:22:58 +08:00
|
|
|
int migratetype)
|
2007-10-16 16:26:11 +08:00
|
|
|
{
|
|
|
|
unsigned long pfn;
|
|
|
|
struct page *page;
|
2022-09-07 14:08:42 +08:00
|
|
|
unsigned long isolate_start = pageblock_start_pfn(start_pfn);
|
2022-09-07 14:08:43 +08:00
|
|
|
unsigned long isolate_end = pageblock_align(end_pfn);
|
2016-01-16 08:57:13 +08:00
|
|
|
|
2022-05-13 11:22:58 +08:00
|
|
|
for (pfn = isolate_start;
|
|
|
|
pfn < isolate_end;
|
2007-10-16 16:26:11 +08:00
|
|
|
pfn += pageblock_nr_pages) {
|
|
|
|
page = __first_valid_page(pfn, pageblock_nr_pages);
|
2017-05-04 05:52:55 +08:00
|
|
|
if (!page || !is_migrate_isolate_page(page))
|
2007-10-16 16:26:11 +08:00
|
|
|
continue;
|
2012-04-03 21:06:15 +08:00
|
|
|
unset_migratetype_isolate(page, migratetype);
|
2007-10-16 16:26:11 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Test all pages in the range is free(means isolated) or not.
|
|
|
|
* all pages in [start_pfn...end_pfn) must be in the same zone.
|
|
|
|
* zone->lock must be held before call this.
|
|
|
|
*
|
2016-04-02 05:31:37 +08:00
|
|
|
* Returns the last tested pfn.
|
2007-10-16 16:26:11 +08:00
|
|
|
*/
|
2016-01-15 07:18:39 +08:00
|
|
|
static unsigned long
|
2012-12-12 08:00:45 +08:00
|
|
|
__test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn,
|
2019-12-01 09:54:07 +08:00
|
|
|
int flags)
|
2007-10-16 16:26:11 +08:00
|
|
|
{
|
|
|
|
struct page *page;
|
|
|
|
|
|
|
|
while (pfn < end_pfn) {
|
|
|
|
page = pfn_to_page(pfn);
|
mm, page_isolation: remove bogus tests for isolated pages
The __test_page_isolated_in_pageblock() is used to verify whether all
pages in pageblock were either successfully isolated, or are hwpoisoned.
Two of the possible state of pages, that are tested, are however bogus
and misleading.
Both tests rely on get_freepage_migratetype(page), which however has no
guarantees about pages on freelists. Specifically, it doesn't guarantee
that the migratetype returned by the function actually matches the
migratetype of the freelist that the page is on. Such guarantee is not
its purpose and would have negative impact on allocator performance.
The first test checks whether the freepage_migratetype equals
MIGRATE_ISOLATE, supposedly to catch races between page isolation and
allocator activity. These races should be fixed nowadays with
51bb1a4093 ("mm/page_alloc: add freepage on isolate pageblock to correct
buddy list") and related patches. As explained above, the check
wouldn't be able to catch them reliably anyway. For the same reason
false positives can happen, although they are harmless, as the
move_freepages() call would just move the page to the same freelist it's
already on. So removing the test is not a bug fix, just cleanup. After
this patch, we assume that all PageBuddy pages are on the correct
freelist and that the races were really fixed. A truly reliable
verification in the form of e.g. VM_BUG_ON() would be complicated and
is arguably not needed.
The second test (page_count(page) == 0 && get_freepage_migratetype(page)
== MIGRATE_ISOLATE) is probably supposed (the code comes from a big
memory isolation patch from 2007) to catch pages on MIGRATE_ISOLATE
pcplists. However, pcplists don't contain MIGRATE_ISOLATE freepages
nowadays, those are freed directly to free lists, so the check is
obsolete. Remove it as well.
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
Acked-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Minchan Kim <minchan@kernel.org>
Acked-by: Michal Nazarewicz <mina86@mina86.com>
Cc: Laura Abbott <lauraa@codeaurora.org>
Reviewed-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: Seungho Park <seungho1.park@lge.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
Acked-by: Mel Gorman <mgorman@techsingularity.net>
Cc: David Rientjes <rientjes@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2015-09-09 06:01:22 +08:00
|
|
|
if (PageBuddy(page))
|
2012-10-09 07:32:16 +08:00
|
|
|
/*
|
mm, page_isolation: remove bogus tests for isolated pages
The __test_page_isolated_in_pageblock() is used to verify whether all
pages in pageblock were either successfully isolated, or are hwpoisoned.
Two of the possible state of pages, that are tested, are however bogus
and misleading.
Both tests rely on get_freepage_migratetype(page), which however has no
guarantees about pages on freelists. Specifically, it doesn't guarantee
that the migratetype returned by the function actually matches the
migratetype of the freelist that the page is on. Such guarantee is not
its purpose and would have negative impact on allocator performance.
The first test checks whether the freepage_migratetype equals
MIGRATE_ISOLATE, supposedly to catch races between page isolation and
allocator activity. These races should be fixed nowadays with
51bb1a4093 ("mm/page_alloc: add freepage on isolate pageblock to correct
buddy list") and related patches. As explained above, the check
wouldn't be able to catch them reliably anyway. For the same reason
false positives can happen, although they are harmless, as the
move_freepages() call would just move the page to the same freelist it's
already on. So removing the test is not a bug fix, just cleanup. After
this patch, we assume that all PageBuddy pages are on the correct
freelist and that the races were really fixed. A truly reliable
verification in the form of e.g. VM_BUG_ON() would be complicated and
is arguably not needed.
The second test (page_count(page) == 0 && get_freepage_migratetype(page)
== MIGRATE_ISOLATE) is probably supposed (the code comes from a big
memory isolation patch from 2007) to catch pages on MIGRATE_ISOLATE
pcplists. However, pcplists don't contain MIGRATE_ISOLATE freepages
nowadays, those are freed directly to free lists, so the check is
obsolete. Remove it as well.
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
Acked-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Minchan Kim <minchan@kernel.org>
Acked-by: Michal Nazarewicz <mina86@mina86.com>
Cc: Laura Abbott <lauraa@codeaurora.org>
Reviewed-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: Seungho Park <seungho1.park@lge.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
Acked-by: Mel Gorman <mgorman@techsingularity.net>
Cc: David Rientjes <rientjes@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2015-09-09 06:01:22 +08:00
|
|
|
* If the page is on a free list, it has to be on
|
|
|
|
* the correct MIGRATE_ISOLATE freelist. There is no
|
|
|
|
* simple way to verify that as VM_BUG_ON(), though.
|
2012-10-09 07:32:16 +08:00
|
|
|
*/
|
2020-10-16 11:10:15 +08:00
|
|
|
pfn += 1 << buddy_order(page);
|
2019-12-01 09:54:07 +08:00
|
|
|
else if ((flags & MEMORY_OFFLINE) && PageHWPoison(page))
|
mm, page_isolation: remove bogus tests for isolated pages
The __test_page_isolated_in_pageblock() is used to verify whether all
pages in pageblock were either successfully isolated, or are hwpoisoned.
Two of the possible state of pages, that are tested, are however bogus
and misleading.
Both tests rely on get_freepage_migratetype(page), which however has no
guarantees about pages on freelists. Specifically, it doesn't guarantee
that the migratetype returned by the function actually matches the
migratetype of the freelist that the page is on. Such guarantee is not
its purpose and would have negative impact on allocator performance.
The first test checks whether the freepage_migratetype equals
MIGRATE_ISOLATE, supposedly to catch races between page isolation and
allocator activity. These races should be fixed nowadays with
51bb1a4093 ("mm/page_alloc: add freepage on isolate pageblock to correct
buddy list") and related patches. As explained above, the check
wouldn't be able to catch them reliably anyway. For the same reason
false positives can happen, although they are harmless, as the
move_freepages() call would just move the page to the same freelist it's
already on. So removing the test is not a bug fix, just cleanup. After
this patch, we assume that all PageBuddy pages are on the correct
freelist and that the races were really fixed. A truly reliable
verification in the form of e.g. VM_BUG_ON() would be complicated and
is arguably not needed.
The second test (page_count(page) == 0 && get_freepage_migratetype(page)
== MIGRATE_ISOLATE) is probably supposed (the code comes from a big
memory isolation patch from 2007) to catch pages on MIGRATE_ISOLATE
pcplists. However, pcplists don't contain MIGRATE_ISOLATE freepages
nowadays, those are freed directly to free lists, so the check is
obsolete. Remove it as well.
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
Acked-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Minchan Kim <minchan@kernel.org>
Acked-by: Michal Nazarewicz <mina86@mina86.com>
Cc: Laura Abbott <lauraa@codeaurora.org>
Reviewed-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: Seungho Park <seungho1.park@lge.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
Acked-by: Mel Gorman <mgorman@techsingularity.net>
Cc: David Rientjes <rientjes@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2015-09-09 06:01:22 +08:00
|
|
|
/* A HWPoisoned page cannot be also PageBuddy */
|
2012-12-12 08:00:45 +08:00
|
|
|
pfn++;
|
mm: Allow to offline unmovable PageOffline() pages via MEM_GOING_OFFLINE
virtio-mem wants to allow to offline memory blocks of which some parts
were unplugged (allocated via alloc_contig_range()), especially, to later
offline and remove completely unplugged memory blocks. The important part
is that PageOffline() has to remain set until the section is offline, so
these pages will never get accessed (e.g., when dumping). The pages should
not be handed back to the buddy (which would require clearing PageOffline()
and result in issues if offlining fails and the pages are suddenly in the
buddy).
Let's allow to do that by allowing to isolate any PageOffline() page
when offlining. This way, we can reach the memory hotplug notifier
MEM_GOING_OFFLINE, where the driver can signal that he is fine with
offlining this page by dropping its reference count. PageOffline() pages
with a reference count of 0 can then be skipped when offlining the
pages (like if they were free, however they are not in the buddy).
Anybody who uses PageOffline() pages and does not agree to offline them
(e.g., Hyper-V balloon, XEN balloon, VMWare balloon for 2MB pages) will not
decrement the reference count and make offlining fail when trying to
migrate such an unmovable page. So there should be no observable change.
Same applies to balloon compaction users (movable PageOffline() pages), the
pages will simply be migrated.
Note 1: If offlining fails, a driver has to increment the reference
count again in MEM_CANCEL_OFFLINE.
Note 2: A driver that makes use of this has to be aware that re-onlining
the memory block has to be handled by hooking into onlining code
(online_page_callback_t), resetting the page PageOffline() and
not giving them to the buddy.
Reviewed-by: Alexander Duyck <alexander.h.duyck@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Tested-by: Pankaj Gupta <pankaj.gupta.linux@gmail.com>
Acked-by: Andrew Morton <akpm@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Juergen Gross <jgross@suse.com>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: Pavel Tatashin <pavel.tatashin@microsoft.com>
Cc: Alexander Duyck <alexander.h.duyck@linux.intel.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Anthony Yznaga <anthony.yznaga@oracle.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Mike Rapoport <rppt@linux.ibm.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Anshuman Khandual <anshuman.khandual@arm.com>
Cc: Qian Cai <cai@lca.pw>
Cc: Pingfan Liu <kernelfans@gmail.com>
Signed-off-by: David Hildenbrand <david@redhat.com>
Link: https://lore.kernel.org/r/20200507140139.17083-7-david@redhat.com
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2020-05-07 22:01:30 +08:00
|
|
|
else if ((flags & MEMORY_OFFLINE) && PageOffline(page) &&
|
|
|
|
!page_count(page))
|
|
|
|
/*
|
|
|
|
* The responsible driver agreed to skip PageOffline()
|
|
|
|
* pages when offlining memory by dropping its
|
|
|
|
* reference in MEM_GOING_OFFLINE.
|
|
|
|
*/
|
|
|
|
pfn++;
|
2007-10-16 16:26:11 +08:00
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
2016-01-15 07:18:39 +08:00
|
|
|
|
|
|
|
return pfn;
|
2007-10-16 16:26:11 +08:00
|
|
|
}
|
|
|
|
|
2016-05-20 08:12:06 +08:00
|
|
|
/* Caller should ensure that requested range is in a single zone */
|
2012-12-12 08:00:45 +08:00
|
|
|
int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn,
|
2019-12-01 09:54:07 +08:00
|
|
|
int isol_flags)
|
2007-10-16 16:26:11 +08:00
|
|
|
{
|
memory hotplug: missing zone->lock in test_pages_isolated()
__test_page_isolated_in_pageblock() in mm/page_isolation.c has a comment
saying that the caller must hold zone->lock. But the only caller of that
function, test_pages_isolated(), does not hold zone->lock and the lock is
also not acquired anywhere before. This patch adds the missing zone->lock
to test_pages_isolated().
We reproducibly run into BUG_ON(!PageBuddy(page)) in __offline_isolated_pages()
during memory hotplug stress test, see trace below. This patch fixes that
problem, it would be good if we could have it in 2.6.27.
kernel BUG at /home/autobuild/BUILD/linux-2.6.26-20080909/mm/page_alloc.c:4561!
illegal operation: 0001 [#1] PREEMPT SMP
Modules linked in: dm_multipath sunrpc bonding qeth_l3 dm_mod qeth ccwgroup vmur
CPU: 1 Not tainted 2.6.26-29.x.20080909-s390default #1
Process memory_loop_all (pid: 10025, task: 2f444028, ksp: 2b10dd28)
Krnl PSW : 040c0000 801727ea (__offline_isolated_pages+0x18e/0x1c4)
R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:0 CC:0 PM:0
Krnl GPRS: 00000000 7e27fc00 00000000 7e27fc00
00000000 00000400 00014000 7e27fc01
00606f00 7e27fc00 00013fe0 2b10dd28
00000005 80172662 801727b2 2b10dd28
Krnl Code: 801727de: 5810900c l %r1,12(%r9)
801727e2: a7f4ffb3 brc 15,80172748
801727e6: a7f40001 brc 15,801727e8
>801727ea: a7f4ffbc brc 15,80172762
801727ee: a7f40001 brc 15,801727f0
801727f2: a7f4ffaf brc 15,80172750
801727f6: 0707 bcr 0,%r7
801727f8: 0017 unknown
Call Trace:
([<0000000000172772>] __offline_isolated_pages+0x116/0x1c4)
[<00000000001953a2>] offline_isolated_pages_cb+0x22/0x34
[<000000000013164c>] walk_memory_resource+0xcc/0x11c
[<000000000019520e>] offline_pages+0x36a/0x498
[<00000000001004d6>] remove_memory+0x36/0x44
[<000000000028fb06>] memory_block_change_state+0x112/0x150
[<000000000028ffb8>] store_mem_state+0x90/0xe4
[<0000000000289c00>] sysdev_store+0x34/0x40
[<00000000001ee048>] sysfs_write_file+0xd0/0x178
[<000000000019b1a8>] vfs_write+0x74/0x118
[<000000000019b9ae>] sys_write+0x46/0x7c
[<000000000011160e>] sysc_do_restart+0x12/0x16
[<0000000077f3e8ca>] 0x77f3e8ca
Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Acked-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-10-03 05:50:16 +08:00
|
|
|
unsigned long pfn, flags;
|
2007-10-16 16:26:11 +08:00
|
|
|
struct page *page;
|
memory hotplug: missing zone->lock in test_pages_isolated()
__test_page_isolated_in_pageblock() in mm/page_isolation.c has a comment
saying that the caller must hold zone->lock. But the only caller of that
function, test_pages_isolated(), does not hold zone->lock and the lock is
also not acquired anywhere before. This patch adds the missing zone->lock
to test_pages_isolated().
We reproducibly run into BUG_ON(!PageBuddy(page)) in __offline_isolated_pages()
during memory hotplug stress test, see trace below. This patch fixes that
problem, it would be good if we could have it in 2.6.27.
kernel BUG at /home/autobuild/BUILD/linux-2.6.26-20080909/mm/page_alloc.c:4561!
illegal operation: 0001 [#1] PREEMPT SMP
Modules linked in: dm_multipath sunrpc bonding qeth_l3 dm_mod qeth ccwgroup vmur
CPU: 1 Not tainted 2.6.26-29.x.20080909-s390default #1
Process memory_loop_all (pid: 10025, task: 2f444028, ksp: 2b10dd28)
Krnl PSW : 040c0000 801727ea (__offline_isolated_pages+0x18e/0x1c4)
R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:0 CC:0 PM:0
Krnl GPRS: 00000000 7e27fc00 00000000 7e27fc00
00000000 00000400 00014000 7e27fc01
00606f00 7e27fc00 00013fe0 2b10dd28
00000005 80172662 801727b2 2b10dd28
Krnl Code: 801727de: 5810900c l %r1,12(%r9)
801727e2: a7f4ffb3 brc 15,80172748
801727e6: a7f40001 brc 15,801727e8
>801727ea: a7f4ffbc brc 15,80172762
801727ee: a7f40001 brc 15,801727f0
801727f2: a7f4ffaf brc 15,80172750
801727f6: 0707 bcr 0,%r7
801727f8: 0017 unknown
Call Trace:
([<0000000000172772>] __offline_isolated_pages+0x116/0x1c4)
[<00000000001953a2>] offline_isolated_pages_cb+0x22/0x34
[<000000000013164c>] walk_memory_resource+0xcc/0x11c
[<000000000019520e>] offline_pages+0x36a/0x498
[<00000000001004d6>] remove_memory+0x36/0x44
[<000000000028fb06>] memory_block_change_state+0x112/0x150
[<000000000028ffb8>] store_mem_state+0x90/0xe4
[<0000000000289c00>] sysdev_store+0x34/0x40
[<00000000001ee048>] sysfs_write_file+0xd0/0x178
[<000000000019b1a8>] vfs_write+0x74/0x118
[<000000000019b9ae>] sys_write+0x46/0x7c
[<000000000011160e>] sysc_do_restart+0x12/0x16
[<0000000077f3e8ca>] 0x77f3e8ca
Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Acked-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-10-03 05:50:16 +08:00
|
|
|
struct zone *zone;
|
2021-09-03 05:58:16 +08:00
|
|
|
int ret;
|
2007-10-16 16:26:11 +08:00
|
|
|
|
|
|
|
/*
|
2013-06-20 18:10:19 +08:00
|
|
|
* Note: pageblock_nr_pages != MAX_ORDER. Then, chunks of free pages
|
|
|
|
* are not aligned to pageblock_nr_pages.
|
|
|
|
* Then we just check migratetype first.
|
2007-10-16 16:26:11 +08:00
|
|
|
*/
|
|
|
|
for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) {
|
|
|
|
page = __first_valid_page(pfn, pageblock_nr_pages);
|
2017-05-04 05:52:55 +08:00
|
|
|
if (page && !is_migrate_isolate_page(page))
|
2007-10-16 16:26:11 +08:00
|
|
|
break;
|
|
|
|
}
|
2008-11-07 04:53:36 +08:00
|
|
|
page = __first_valid_page(start_pfn, end_pfn - start_pfn);
|
2021-09-03 05:58:16 +08:00
|
|
|
if ((pfn < end_pfn) || !page) {
|
|
|
|
ret = -EBUSY;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2013-06-20 18:10:19 +08:00
|
|
|
/* Check all pages are free or marked as ISOLATED */
|
2008-11-07 04:53:36 +08:00
|
|
|
zone = page_zone(page);
|
memory hotplug: missing zone->lock in test_pages_isolated()
__test_page_isolated_in_pageblock() in mm/page_isolation.c has a comment
saying that the caller must hold zone->lock. But the only caller of that
function, test_pages_isolated(), does not hold zone->lock and the lock is
also not acquired anywhere before. This patch adds the missing zone->lock
to test_pages_isolated().
We reproducibly run into BUG_ON(!PageBuddy(page)) in __offline_isolated_pages()
during memory hotplug stress test, see trace below. This patch fixes that
problem, it would be good if we could have it in 2.6.27.
kernel BUG at /home/autobuild/BUILD/linux-2.6.26-20080909/mm/page_alloc.c:4561!
illegal operation: 0001 [#1] PREEMPT SMP
Modules linked in: dm_multipath sunrpc bonding qeth_l3 dm_mod qeth ccwgroup vmur
CPU: 1 Not tainted 2.6.26-29.x.20080909-s390default #1
Process memory_loop_all (pid: 10025, task: 2f444028, ksp: 2b10dd28)
Krnl PSW : 040c0000 801727ea (__offline_isolated_pages+0x18e/0x1c4)
R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:0 CC:0 PM:0
Krnl GPRS: 00000000 7e27fc00 00000000 7e27fc00
00000000 00000400 00014000 7e27fc01
00606f00 7e27fc00 00013fe0 2b10dd28
00000005 80172662 801727b2 2b10dd28
Krnl Code: 801727de: 5810900c l %r1,12(%r9)
801727e2: a7f4ffb3 brc 15,80172748
801727e6: a7f40001 brc 15,801727e8
>801727ea: a7f4ffbc brc 15,80172762
801727ee: a7f40001 brc 15,801727f0
801727f2: a7f4ffaf brc 15,80172750
801727f6: 0707 bcr 0,%r7
801727f8: 0017 unknown
Call Trace:
([<0000000000172772>] __offline_isolated_pages+0x116/0x1c4)
[<00000000001953a2>] offline_isolated_pages_cb+0x22/0x34
[<000000000013164c>] walk_memory_resource+0xcc/0x11c
[<000000000019520e>] offline_pages+0x36a/0x498
[<00000000001004d6>] remove_memory+0x36/0x44
[<000000000028fb06>] memory_block_change_state+0x112/0x150
[<000000000028ffb8>] store_mem_state+0x90/0xe4
[<0000000000289c00>] sysdev_store+0x34/0x40
[<00000000001ee048>] sysfs_write_file+0xd0/0x178
[<000000000019b1a8>] vfs_write+0x74/0x118
[<000000000019b9ae>] sys_write+0x46/0x7c
[<000000000011160e>] sysc_do_restart+0x12/0x16
[<0000000077f3e8ca>] 0x77f3e8ca
Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Acked-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-10-03 05:50:16 +08:00
|
|
|
spin_lock_irqsave(&zone->lock, flags);
|
2019-12-01 09:54:07 +08:00
|
|
|
pfn = __test_page_isolated_in_pageblock(start_pfn, end_pfn, isol_flags);
|
memory hotplug: missing zone->lock in test_pages_isolated()
__test_page_isolated_in_pageblock() in mm/page_isolation.c has a comment
saying that the caller must hold zone->lock. But the only caller of that
function, test_pages_isolated(), does not hold zone->lock and the lock is
also not acquired anywhere before. This patch adds the missing zone->lock
to test_pages_isolated().
We reproducibly run into BUG_ON(!PageBuddy(page)) in __offline_isolated_pages()
during memory hotplug stress test, see trace below. This patch fixes that
problem, it would be good if we could have it in 2.6.27.
kernel BUG at /home/autobuild/BUILD/linux-2.6.26-20080909/mm/page_alloc.c:4561!
illegal operation: 0001 [#1] PREEMPT SMP
Modules linked in: dm_multipath sunrpc bonding qeth_l3 dm_mod qeth ccwgroup vmur
CPU: 1 Not tainted 2.6.26-29.x.20080909-s390default #1
Process memory_loop_all (pid: 10025, task: 2f444028, ksp: 2b10dd28)
Krnl PSW : 040c0000 801727ea (__offline_isolated_pages+0x18e/0x1c4)
R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:0 CC:0 PM:0
Krnl GPRS: 00000000 7e27fc00 00000000 7e27fc00
00000000 00000400 00014000 7e27fc01
00606f00 7e27fc00 00013fe0 2b10dd28
00000005 80172662 801727b2 2b10dd28
Krnl Code: 801727de: 5810900c l %r1,12(%r9)
801727e2: a7f4ffb3 brc 15,80172748
801727e6: a7f40001 brc 15,801727e8
>801727ea: a7f4ffbc brc 15,80172762
801727ee: a7f40001 brc 15,801727f0
801727f2: a7f4ffaf brc 15,80172750
801727f6: 0707 bcr 0,%r7
801727f8: 0017 unknown
Call Trace:
([<0000000000172772>] __offline_isolated_pages+0x116/0x1c4)
[<00000000001953a2>] offline_isolated_pages_cb+0x22/0x34
[<000000000013164c>] walk_memory_resource+0xcc/0x11c
[<000000000019520e>] offline_pages+0x36a/0x498
[<00000000001004d6>] remove_memory+0x36/0x44
[<000000000028fb06>] memory_block_change_state+0x112/0x150
[<000000000028ffb8>] store_mem_state+0x90/0xe4
[<0000000000289c00>] sysdev_store+0x34/0x40
[<00000000001ee048>] sysfs_write_file+0xd0/0x178
[<000000000019b1a8>] vfs_write+0x74/0x118
[<000000000019b9ae>] sys_write+0x46/0x7c
[<000000000011160e>] sysc_do_restart+0x12/0x16
[<0000000077f3e8ca>] 0x77f3e8ca
Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Acked-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-10-03 05:50:16 +08:00
|
|
|
spin_unlock_irqrestore(&zone->lock, flags);
|
2016-01-15 07:18:39 +08:00
|
|
|
|
2021-09-03 05:58:16 +08:00
|
|
|
ret = pfn < end_pfn ? -EBUSY : 0;
|
|
|
|
|
|
|
|
out:
|
2016-01-15 07:18:42 +08:00
|
|
|
trace_test_pages_isolated(start_pfn, end_pfn, pfn);
|
|
|
|
|
2021-09-03 05:58:16 +08:00
|
|
|
return ret;
|
2007-10-16 16:26:11 +08:00
|
|
|
}
|