Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 230734
b: refs/heads/master
c: 9950474
h: refs/heads/master
v: v3
  • Loading branch information
Mel Gorman authored and Linus Torvalds committed Jan 14, 2011
1 parent 703f999 commit 3771c73
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 14 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: c585a2678d83ba8fb02fa6b197de0ac7d67377f1
refs/heads/master: 9950474883e027e6e728cbcff25f7f2bf0c96530
3 changes: 2 additions & 1 deletion trunk/include/linux/mmzone.h
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,7 @@ typedef struct pglist_data {
wait_queue_head_t kswapd_wait;
struct task_struct *kswapd;
int kswapd_max_order;
enum zone_type classzone_idx;
} pg_data_t;

#define node_present_pages(nid) (NODE_DATA(nid)->node_present_pages)
Expand All @@ -654,7 +655,7 @@ typedef struct pglist_data {

extern struct mutex zonelists_mutex;
void build_all_zonelists(void *data);
void wakeup_kswapd(struct zone *zone, int order);
void wakeup_kswapd(struct zone *zone, int order, enum zone_type classzone_idx);
bool zone_watermark_ok(struct zone *z, int order, unsigned long mark,
int classzone_idx, int alloc_flags);
bool zone_watermark_ok_safe(struct zone *z, int order, unsigned long mark,
Expand Down
8 changes: 5 additions & 3 deletions trunk/mm/page_alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1944,13 +1944,14 @@ __alloc_pages_high_priority(gfp_t gfp_mask, unsigned int order,

static inline
void wake_all_kswapd(unsigned int order, struct zonelist *zonelist,
enum zone_type high_zoneidx)
enum zone_type high_zoneidx,
enum zone_type classzone_idx)
{
struct zoneref *z;
struct zone *zone;

for_each_zone_zonelist(zone, z, zonelist, high_zoneidx)
wakeup_kswapd(zone, order);
wakeup_kswapd(zone, order, classzone_idx);
}

static inline int
Expand Down Expand Up @@ -2028,7 +2029,8 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
goto nopage;

restart:
wake_all_kswapd(order, zonelist, high_zoneidx);
wake_all_kswapd(order, zonelist, high_zoneidx,
zone_idx(preferred_zone));

/*
* OK, we're below the kswapd watermark and have kicked background
Expand Down
68 changes: 59 additions & 9 deletions trunk/mm/vmscan.c
Original file line number Diff line number Diff line change
Expand Up @@ -2246,11 +2246,14 @@ static int sleeping_prematurely(pg_data_t *pgdat, int order, long remaining)
* interoperates with the page allocator fallback scheme to ensure that aging
* of pages is balanced across the zones.
*/
static unsigned long balance_pgdat(pg_data_t *pgdat, int order)
static unsigned long balance_pgdat(pg_data_t *pgdat, int order,
int classzone_idx)
{
int all_zones_ok;
int any_zone_ok;
int priority;
int i;
int end_zone = 0; /* Inclusive. 0 = ZONE_DMA */
unsigned long total_scanned;
struct reclaim_state *reclaim_state = current->reclaim_state;
struct scan_control sc = {
Expand All @@ -2273,7 +2276,6 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order)
count_vm_event(PAGEOUTRUN);

for (priority = DEF_PRIORITY; priority >= 0; priority--) {
int end_zone = 0; /* Inclusive. 0 = ZONE_DMA */
unsigned long lru_pages = 0;
int has_under_min_watermark_zone = 0;

Expand All @@ -2282,6 +2284,7 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order)
disable_swap_token();

all_zones_ok = 1;
any_zone_ok = 0;

/*
* Scan in the highmem->dma direction for the highest
Expand Down Expand Up @@ -2400,10 +2403,12 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order)
* spectulatively avoid congestion waits
*/
zone_clear_flag(zone, ZONE_CONGESTED);
if (i <= classzone_idx)
any_zone_ok = 1;
}

}
if (all_zones_ok)
if (all_zones_ok || (order && any_zone_ok))
break; /* kswapd: all done */
/*
* OK, kswapd is getting into trouble. Take a nap, then take
Expand All @@ -2426,7 +2431,13 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order)
break;
}
out:
if (!all_zones_ok) {

/*
* order-0: All zones must meet high watermark for a balanced node
* high-order: Any zone below pgdats classzone_idx must meet the high
* watermark for a balanced node
*/
if (!(all_zones_ok || (order && any_zone_ok))) {
cond_resched();

try_to_freeze();
Expand All @@ -2451,6 +2462,36 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order)
goto loop_again;
}

/*
* If kswapd was reclaiming at a higher order, it has the option of
* sleeping without all zones being balanced. Before it does, it must
* ensure that the watermarks for order-0 on *all* zones are met and
* that the congestion flags are cleared. The congestion flag must
* be cleared as kswapd is the only mechanism that clears the flag
* and it is potentially going to sleep here.
*/
if (order) {
for (i = 0; i <= end_zone; i++) {
struct zone *zone = pgdat->node_zones + i;

if (!populated_zone(zone))
continue;

if (zone->all_unreclaimable && priority != DEF_PRIORITY)
continue;

/* Confirm the zone is balanced for order-0 */
if (!zone_watermark_ok(zone, 0,
high_wmark_pages(zone), 0, 0)) {
order = sc.order = 0;
goto loop_again;
}

/* If balanced, clear the congested flag */
zone_clear_flag(zone, ZONE_CONGESTED);
}
}

return sc.nr_reclaimed;
}

Expand Down Expand Up @@ -2514,6 +2555,7 @@ static void kswapd_try_to_sleep(pg_data_t *pgdat, int order)
static int kswapd(void *p)
{
unsigned long order;
int classzone_idx;
pg_data_t *pgdat = (pg_data_t*)p;
struct task_struct *tsk = current;

Expand Down Expand Up @@ -2544,21 +2586,27 @@ static int kswapd(void *p)
set_freezable();

order = 0;
classzone_idx = MAX_NR_ZONES - 1;
for ( ; ; ) {
unsigned long new_order;
int new_classzone_idx;
int ret;

new_order = pgdat->kswapd_max_order;
new_classzone_idx = pgdat->classzone_idx;
pgdat->kswapd_max_order = 0;
if (order < new_order) {
pgdat->classzone_idx = MAX_NR_ZONES - 1;
if (order < new_order || classzone_idx > new_classzone_idx) {
/*
* Don't sleep if someone wants a larger 'order'
* allocation
* allocation or has tigher zone constraints
*/
order = new_order;
classzone_idx = new_classzone_idx;
} else {
kswapd_try_to_sleep(pgdat, order);
order = pgdat->kswapd_max_order;
classzone_idx = pgdat->classzone_idx;
}

ret = try_to_freeze();
Expand All @@ -2571,7 +2619,7 @@ static int kswapd(void *p)
*/
if (!ret) {
trace_mm_vmscan_kswapd_wake(pgdat->node_id, order);
balance_pgdat(pgdat, order);
balance_pgdat(pgdat, order, classzone_idx);
}
}
return 0;
Expand All @@ -2580,7 +2628,7 @@ static int kswapd(void *p)
/*
* A zone is low on free memory, so wake its kswapd task to service it.
*/
void wakeup_kswapd(struct zone *zone, int order)
void wakeup_kswapd(struct zone *zone, int order, enum zone_type classzone_idx)
{
pg_data_t *pgdat;

Expand All @@ -2590,8 +2638,10 @@ void wakeup_kswapd(struct zone *zone, int order)
if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
return;
pgdat = zone->zone_pgdat;
if (pgdat->kswapd_max_order < order)
if (pgdat->kswapd_max_order < order) {
pgdat->kswapd_max_order = order;
pgdat->classzone_idx = min(pgdat->classzone_idx, classzone_idx);
}
if (!waitqueue_active(&pgdat->kswapd_wait))
return;
if (zone_watermark_ok_safe(zone, order, low_wmark_pages(zone), 0, 0))
Expand Down

0 comments on commit 3771c73

Please sign in to comment.