mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 11:11:45 -04:00
mm/vmstat: fix overflow in mod_zone_page_state()
mod_zone_page_state() takes a "delta" integer argument. delta contains
the number of pages that should be added or subtracted from a struct
zone's vm_stat field.
If a zone is larger than 8TB this will cause overflows. E.g. for a
zone with a size slightly larger than 8TB the line
mod_zone_page_state(zone, NR_ALLOC_BATCH, zone->managed_pages);
in mm/page_alloc.c:free_area_init_core() will result in a negative
result for the NR_ALLOC_BATCH entry within the zone's vm_stat, since 8TB
contain 0x8xxxxxxx pages which will be sign extended to a negative
value.
Fix this by changing the delta argument to long type.
This could fix an early boot problem seen on s390, where we have a 9TB
system with only one node. ZONE_DMA contains 2GB and ZONE_NORMAL the
rest. The system is trying to allocate a GFP_DMA page but ZONE_DMA is
completely empty, so it tries to reclaim pages in an endless loop.
This was seen on a heavily patched 3.10 kernel. One possible
explaination seem to be the overflows caused by mod_zone_page_state().
Unfortunately I did not have the chance to verify that this patch
actually fixes the problem, since I don't have access to the system
right now. However the overflow problem does exist anyway.
Given the description that a system with slightly less than 8TB does
work, this seems to be a candidate for the observed problem.
Signed-off-by: Heiko Carstens <[email protected]>
Cc: Christoph Lameter <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
This commit is contained in:
parent
cc28d6d80f
commit
6cdb18ad98
2 changed files with 8 additions and 8 deletions
10
mm/vmstat.c
10
mm/vmstat.c
|
|
@ -219,7 +219,7 @@ void set_pgdat_percpu_threshold(pg_data_t *pgdat,
|
|||
* particular counter cannot be updated from interrupt context.
|
||||
*/
|
||||
void __mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
|
||||
int delta)
|
||||
long delta)
|
||||
{
|
||||
struct per_cpu_pageset __percpu *pcp = zone->pageset;
|
||||
s8 __percpu *p = pcp->vm_stat_diff + item;
|
||||
|
|
@ -318,8 +318,8 @@ EXPORT_SYMBOL(__dec_zone_page_state);
|
|||
* 1 Overstepping half of threshold
|
||||
* -1 Overstepping minus half of threshold
|
||||
*/
|
||||
static inline void mod_state(struct zone *zone,
|
||||
enum zone_stat_item item, int delta, int overstep_mode)
|
||||
static inline void mod_state(struct zone *zone, enum zone_stat_item item,
|
||||
long delta, int overstep_mode)
|
||||
{
|
||||
struct per_cpu_pageset __percpu *pcp = zone->pageset;
|
||||
s8 __percpu *p = pcp->vm_stat_diff + item;
|
||||
|
|
@ -357,7 +357,7 @@ static inline void mod_state(struct zone *zone,
|
|||
}
|
||||
|
||||
void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
|
||||
int delta)
|
||||
long delta)
|
||||
{
|
||||
mod_state(zone, item, delta, 0);
|
||||
}
|
||||
|
|
@ -384,7 +384,7 @@ EXPORT_SYMBOL(dec_zone_page_state);
|
|||
* Use interrupt disable to serialize counter updates
|
||||
*/
|
||||
void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
|
||||
int delta)
|
||||
long delta)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue