diff options
-rw-r--r-- | Documentation/trace/postprocess/trace-vmscan-postprocess.pl | 4 | ||||
-rw-r--r-- | include/linux/mmzone.h | 3 | ||||
-rw-r--r-- | include/trace/events/vmscan.h | 17 | ||||
-rw-r--r-- | mm/page_alloc.c | 14 | ||||
-rw-r--r-- | mm/vmscan.c | 32 |
5 files changed, 45 insertions, 25 deletions
diff --git a/Documentation/trace/postprocess/trace-vmscan-postprocess.pl b/Documentation/trace/postprocess/trace-vmscan-postprocess.pl index ba976805853a..66bfd8396877 100644 --- a/Documentation/trace/postprocess/trace-vmscan-postprocess.pl +++ b/Documentation/trace/postprocess/trace-vmscan-postprocess.pl | |||
@@ -111,7 +111,7 @@ my $regex_direct_begin_default = 'order=([0-9]*) may_writepage=([0-9]*) gfp_flag | |||
111 | my $regex_direct_end_default = 'nr_reclaimed=([0-9]*)'; | 111 | my $regex_direct_end_default = 'nr_reclaimed=([0-9]*)'; |
112 | my $regex_kswapd_wake_default = 'nid=([0-9]*) order=([0-9]*)'; | 112 | my $regex_kswapd_wake_default = 'nid=([0-9]*) order=([0-9]*)'; |
113 | my $regex_kswapd_sleep_default = 'nid=([0-9]*)'; | 113 | my $regex_kswapd_sleep_default = 'nid=([0-9]*)'; |
114 | my $regex_wakeup_kswapd_default = 'nid=([0-9]*) zid=([0-9]*) order=([0-9]*)'; | 114 | my $regex_wakeup_kswapd_default = 'nid=([0-9]*) zid=([0-9]*) order=([0-9]*) gfp_flags=([A-Z_|]*)'; |
115 | my $regex_lru_isolate_default = 'isolate_mode=([0-9]*) classzone_idx=([0-9]*) order=([0-9]*) nr_requested=([0-9]*) nr_scanned=([0-9]*) nr_skipped=([0-9]*) nr_taken=([0-9]*) lru=([a-z_]*)'; | 115 | my $regex_lru_isolate_default = 'isolate_mode=([0-9]*) classzone_idx=([0-9]*) order=([0-9]*) nr_requested=([0-9]*) nr_scanned=([0-9]*) nr_skipped=([0-9]*) nr_taken=([0-9]*) lru=([a-z_]*)'; |
116 | my $regex_lru_shrink_inactive_default = 'nid=([0-9]*) nr_scanned=([0-9]*) nr_reclaimed=([0-9]*) nr_dirty=([0-9]*) nr_writeback=([0-9]*) nr_congested=([0-9]*) nr_immediate=([0-9]*) nr_activate=([0-9]*) nr_ref_keep=([0-9]*) nr_unmap_fail=([0-9]*) priority=([0-9]*) flags=([A-Z_|]*)'; | 116 | my $regex_lru_shrink_inactive_default = 'nid=([0-9]*) nr_scanned=([0-9]*) nr_reclaimed=([0-9]*) nr_dirty=([0-9]*) nr_writeback=([0-9]*) nr_congested=([0-9]*) nr_immediate=([0-9]*) nr_activate=([0-9]*) nr_ref_keep=([0-9]*) nr_unmap_fail=([0-9]*) priority=([0-9]*) flags=([A-Z_|]*)'; |
117 | my $regex_lru_shrink_active_default = 'lru=([A-Z_]*) nr_scanned=([0-9]*) nr_rotated=([0-9]*) priority=([0-9]*)'; | 117 | my $regex_lru_shrink_active_default = 'lru=([A-Z_]*) nr_scanned=([0-9]*) nr_rotated=([0-9]*) priority=([0-9]*)'; |
@@ -201,7 +201,7 @@ $regex_kswapd_sleep = generate_traceevent_regex( | |||
201 | $regex_wakeup_kswapd = generate_traceevent_regex( | 201 | $regex_wakeup_kswapd = generate_traceevent_regex( |
202 | "vmscan/mm_vmscan_wakeup_kswapd", | 202 | "vmscan/mm_vmscan_wakeup_kswapd", |
203 | $regex_wakeup_kswapd_default, | 203 | $regex_wakeup_kswapd_default, |
204 | "nid", "zid", "order"); | 204 | "nid", "zid", "order", "gfp_flags"); |
205 | $regex_lru_isolate = generate_traceevent_regex( | 205 | $regex_lru_isolate = generate_traceevent_regex( |
206 | "vmscan/mm_vmscan_lru_isolate", | 206 | "vmscan/mm_vmscan_lru_isolate", |
207 | $regex_lru_isolate_default, | 207 | $regex_lru_isolate_default, |
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 5d935411d3c4..f11ae29005f1 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h | |||
@@ -776,7 +776,8 @@ static inline bool is_dev_zone(const struct zone *zone) | |||
776 | #include <linux/memory_hotplug.h> | 776 | #include <linux/memory_hotplug.h> |
777 | 777 | ||
778 | void build_all_zonelists(pg_data_t *pgdat); | 778 | void build_all_zonelists(pg_data_t *pgdat); |
779 | void wakeup_kswapd(struct zone *zone, int order, enum zone_type classzone_idx); | 779 | void wakeup_kswapd(struct zone *zone, gfp_t gfp_mask, int order, |
780 | enum zone_type classzone_idx); | ||
780 | bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, | 781 | bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, |
781 | int classzone_idx, unsigned int alloc_flags, | 782 | int classzone_idx, unsigned int alloc_flags, |
782 | long free_pages); | 783 | long free_pages); |
diff --git a/include/trace/events/vmscan.h b/include/trace/events/vmscan.h index e0b8b9173e1c..6570c5b45ba1 100644 --- a/include/trace/events/vmscan.h +++ b/include/trace/events/vmscan.h | |||
@@ -78,26 +78,29 @@ TRACE_EVENT(mm_vmscan_kswapd_wake, | |||
78 | 78 | ||
79 | TRACE_EVENT(mm_vmscan_wakeup_kswapd, | 79 | TRACE_EVENT(mm_vmscan_wakeup_kswapd, |
80 | 80 | ||
81 | TP_PROTO(int nid, int zid, int order), | 81 | TP_PROTO(int nid, int zid, int order, gfp_t gfp_flags), |
82 | 82 | ||
83 | TP_ARGS(nid, zid, order), | 83 | TP_ARGS(nid, zid, order, gfp_flags), |
84 | 84 | ||
85 | TP_STRUCT__entry( | 85 | TP_STRUCT__entry( |
86 | __field( int, nid ) | 86 | __field( int, nid ) |
87 | __field( int, zid ) | 87 | __field( int, zid ) |
88 | __field( int, order ) | 88 | __field( int, order ) |
89 | __field( gfp_t, gfp_flags ) | ||
89 | ), | 90 | ), |
90 | 91 | ||
91 | TP_fast_assign( | 92 | TP_fast_assign( |
92 | __entry->nid = nid; | 93 | __entry->nid = nid; |
93 | __entry->zid = zid; | 94 | __entry->zid = zid; |
94 | __entry->order = order; | 95 | __entry->order = order; |
96 | __entry->gfp_flags = gfp_flags; | ||
95 | ), | 97 | ), |
96 | 98 | ||
97 | TP_printk("nid=%d zid=%d order=%d", | 99 | TP_printk("nid=%d zid=%d order=%d gfp_flags=%s", |
98 | __entry->nid, | 100 | __entry->nid, |
99 | __entry->zid, | 101 | __entry->zid, |
100 | __entry->order) | 102 | __entry->order, |
103 | show_gfp_flags(__entry->gfp_flags)) | ||
101 | ); | 104 | ); |
102 | 105 | ||
103 | DECLARE_EVENT_CLASS(mm_vmscan_direct_reclaim_begin_template, | 106 | DECLARE_EVENT_CLASS(mm_vmscan_direct_reclaim_begin_template, |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index f6005b7c3446..02c1a60d7937 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -3805,16 +3805,18 @@ retry: | |||
3805 | return page; | 3805 | return page; |
3806 | } | 3806 | } |
3807 | 3807 | ||
3808 | static void wake_all_kswapds(unsigned int order, const struct alloc_context *ac) | 3808 | static void wake_all_kswapds(unsigned int order, gfp_t gfp_mask, |
3809 | const struct alloc_context *ac) | ||
3809 | { | 3810 | { |
3810 | struct zoneref *z; | 3811 | struct zoneref *z; |
3811 | struct zone *zone; | 3812 | struct zone *zone; |
3812 | pg_data_t *last_pgdat = NULL; | 3813 | pg_data_t *last_pgdat = NULL; |
3814 | enum zone_type high_zoneidx = ac->high_zoneidx; | ||
3813 | 3815 | ||
3814 | for_each_zone_zonelist_nodemask(zone, z, ac->zonelist, | 3816 | for_each_zone_zonelist_nodemask(zone, z, ac->zonelist, high_zoneidx, |
3815 | ac->high_zoneidx, ac->nodemask) { | 3817 | ac->nodemask) { |
3816 | if (last_pgdat != zone->zone_pgdat) | 3818 | if (last_pgdat != zone->zone_pgdat) |
3817 | wakeup_kswapd(zone, order, ac->high_zoneidx); | 3819 | wakeup_kswapd(zone, gfp_mask, order, high_zoneidx); |
3818 | last_pgdat = zone->zone_pgdat; | 3820 | last_pgdat = zone->zone_pgdat; |
3819 | } | 3821 | } |
3820 | } | 3822 | } |
@@ -4093,7 +4095,7 @@ retry_cpuset: | |||
4093 | goto nopage; | 4095 | goto nopage; |
4094 | 4096 | ||
4095 | if (gfp_mask & __GFP_KSWAPD_RECLAIM) | 4097 | if (gfp_mask & __GFP_KSWAPD_RECLAIM) |
4096 | wake_all_kswapds(order, ac); | 4098 | wake_all_kswapds(order, gfp_mask, ac); |
4097 | 4099 | ||
4098 | /* | 4100 | /* |
4099 | * The adjusted alloc_flags might result in immediate success, so try | 4101 | * The adjusted alloc_flags might result in immediate success, so try |
@@ -4151,7 +4153,7 @@ retry_cpuset: | |||
4151 | retry: | 4153 | retry: |
4152 | /* Ensure kswapd doesn't accidentally go to sleep as long as we loop */ | 4154 | /* Ensure kswapd doesn't accidentally go to sleep as long as we loop */ |
4153 | if (gfp_mask & __GFP_KSWAPD_RECLAIM) | 4155 | if (gfp_mask & __GFP_KSWAPD_RECLAIM) |
4154 | wake_all_kswapds(order, ac); | 4156 | wake_all_kswapds(order, gfp_mask, ac); |
4155 | 4157 | ||
4156 | reserve_flags = __gfp_pfmemalloc_flags(gfp_mask); | 4158 | reserve_flags = __gfp_pfmemalloc_flags(gfp_mask); |
4157 | if (reserve_flags) | 4159 | if (reserve_flags) |
diff --git a/mm/vmscan.c b/mm/vmscan.c index 976be140a8ce..4390a8d5be41 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c | |||
@@ -3539,16 +3539,21 @@ kswapd_try_sleep: | |||
3539 | } | 3539 | } |
3540 | 3540 | ||
3541 | /* | 3541 | /* |
3542 | * A zone is low on free memory, so wake its kswapd task to service it. | 3542 | * A zone is low on free memory or too fragmented for high-order memory. If |
3543 | * kswapd should reclaim (direct reclaim is deferred), wake it up for the zone's | ||
3544 | * pgdat. It will wake up kcompactd after reclaiming memory. If kswapd reclaim | ||
3545 | * has failed or is not needed, still wake up kcompactd if only compaction is | ||
3546 | * needed. | ||
3543 | */ | 3547 | */ |
3544 | void wakeup_kswapd(struct zone *zone, int order, enum zone_type classzone_idx) | 3548 | void wakeup_kswapd(struct zone *zone, gfp_t gfp_flags, int order, |
3549 | enum zone_type classzone_idx) | ||
3545 | { | 3550 | { |
3546 | pg_data_t *pgdat; | 3551 | pg_data_t *pgdat; |
3547 | 3552 | ||
3548 | if (!managed_zone(zone)) | 3553 | if (!managed_zone(zone)) |
3549 | return; | 3554 | return; |
3550 | 3555 | ||
3551 | if (!cpuset_zone_allowed(zone, GFP_KERNEL | __GFP_HARDWALL)) | 3556 | if (!cpuset_zone_allowed(zone, gfp_flags)) |
3552 | return; | 3557 | return; |
3553 | pgdat = zone->zone_pgdat; | 3558 | pgdat = zone->zone_pgdat; |
3554 | pgdat->kswapd_classzone_idx = kswapd_classzone_idx(pgdat, | 3559 | pgdat->kswapd_classzone_idx = kswapd_classzone_idx(pgdat, |
@@ -3557,14 +3562,23 @@ void wakeup_kswapd(struct zone *zone, int order, enum zone_type classzone_idx) | |||
3557 | if (!waitqueue_active(&pgdat->kswapd_wait)) | 3562 | if (!waitqueue_active(&pgdat->kswapd_wait)) |
3558 | return; | 3563 | return; |
3559 | 3564 | ||
3560 | /* Hopeless node, leave it to direct reclaim */ | 3565 | /* Hopeless node, leave it to direct reclaim if possible */ |
3561 | if (pgdat->kswapd_failures >= MAX_RECLAIM_RETRIES) | 3566 | if (pgdat->kswapd_failures >= MAX_RECLAIM_RETRIES || |
3562 | return; | 3567 | pgdat_balanced(pgdat, order, classzone_idx)) { |
3563 | 3568 | /* | |
3564 | if (pgdat_balanced(pgdat, order, classzone_idx)) | 3569 | * There may be plenty of free memory available, but it's too |
3570 | * fragmented for high-order allocations. Wake up kcompactd | ||
3571 | * and rely on compaction_suitable() to determine if it's | ||
3572 | * needed. If it fails, it will defer subsequent attempts to | ||
3573 | * ratelimit its work. | ||
3574 | */ | ||
3575 | if (!(gfp_flags & __GFP_DIRECT_RECLAIM)) | ||
3576 | wakeup_kcompactd(pgdat, order, classzone_idx); | ||
3565 | return; | 3577 | return; |
3578 | } | ||
3566 | 3579 | ||
3567 | trace_mm_vmscan_wakeup_kswapd(pgdat->node_id, classzone_idx, order); | 3580 | trace_mm_vmscan_wakeup_kswapd(pgdat->node_id, classzone_idx, order, |
3581 | gfp_flags); | ||
3568 | wake_up_interruptible(&pgdat->kswapd_wait); | 3582 | wake_up_interruptible(&pgdat->kswapd_wait); |
3569 | } | 3583 | } |
3570 | 3584 | ||