diff options
-rw-r--r-- | include/linux/compaction.h | 6 | ||||
-rw-r--r-- | mm/compaction.c | 53 | ||||
-rw-r--r-- | mm/vmscan.c | 10 |
3 files changed, 51 insertions, 18 deletions
diff --git a/include/linux/compaction.h b/include/linux/compaction.h index bb2bbdbe5464..7a9323aef4a3 100644 --- a/include/linux/compaction.h +++ b/include/linux/compaction.h | |||
@@ -23,6 +23,7 @@ extern int fragmentation_index(struct zone *zone, unsigned int order); | |||
23 | extern unsigned long try_to_compact_pages(struct zonelist *zonelist, | 23 | extern unsigned long try_to_compact_pages(struct zonelist *zonelist, |
24 | int order, gfp_t gfp_mask, nodemask_t *mask, | 24 | int order, gfp_t gfp_mask, nodemask_t *mask, |
25 | bool sync); | 25 | bool sync); |
26 | extern int compact_pgdat(pg_data_t *pgdat, int order); | ||
26 | extern unsigned long compaction_suitable(struct zone *zone, int order); | 27 | extern unsigned long compaction_suitable(struct zone *zone, int order); |
27 | 28 | ||
28 | /* Do not skip compaction more than 64 times */ | 29 | /* Do not skip compaction more than 64 times */ |
@@ -62,6 +63,11 @@ static inline unsigned long try_to_compact_pages(struct zonelist *zonelist, | |||
62 | return COMPACT_CONTINUE; | 63 | return COMPACT_CONTINUE; |
63 | } | 64 | } |
64 | 65 | ||
66 | static inline int compact_pgdat(pg_data_t *pgdat, int order) | ||
67 | { | ||
68 | return COMPACT_CONTINUE; | ||
69 | } | ||
70 | |||
65 | static inline unsigned long compaction_suitable(struct zone *zone, int order) | 71 | static inline unsigned long compaction_suitable(struct zone *zone, int order) |
66 | { | 72 | { |
67 | return COMPACT_SKIPPED; | 73 | return COMPACT_SKIPPED; |
diff --git a/mm/compaction.c b/mm/compaction.c index d9ebebe1a2aa..36f0f61f4a24 100644 --- a/mm/compaction.c +++ b/mm/compaction.c | |||
@@ -675,44 +675,61 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist, | |||
675 | 675 | ||
676 | 676 | ||
677 | /* Compact all zones within a node */ | 677 | /* Compact all zones within a node */ |
678 | static int compact_node(int nid) | 678 | static int __compact_pgdat(pg_data_t *pgdat, struct compact_control *cc) |
679 | { | 679 | { |
680 | int zoneid; | 680 | int zoneid; |
681 | pg_data_t *pgdat; | ||
682 | struct zone *zone; | 681 | struct zone *zone; |
683 | 682 | ||
684 | if (nid < 0 || nid >= nr_node_ids || !node_online(nid)) | ||
685 | return -EINVAL; | ||
686 | pgdat = NODE_DATA(nid); | ||
687 | |||
688 | /* Flush pending updates to the LRU lists */ | 683 | /* Flush pending updates to the LRU lists */ |
689 | lru_add_drain_all(); | 684 | lru_add_drain_all(); |
690 | 685 | ||
691 | for (zoneid = 0; zoneid < MAX_NR_ZONES; zoneid++) { | 686 | for (zoneid = 0; zoneid < MAX_NR_ZONES; zoneid++) { |
692 | struct compact_control cc = { | ||
693 | .nr_freepages = 0, | ||
694 | .nr_migratepages = 0, | ||
695 | .order = -1, | ||
696 | .sync = true, | ||
697 | }; | ||
698 | 687 | ||
699 | zone = &pgdat->node_zones[zoneid]; | 688 | zone = &pgdat->node_zones[zoneid]; |
700 | if (!populated_zone(zone)) | 689 | if (!populated_zone(zone)) |
701 | continue; | 690 | continue; |
702 | 691 | ||
703 | cc.zone = zone; | 692 | cc->nr_freepages = 0; |
704 | INIT_LIST_HEAD(&cc.freepages); | 693 | cc->nr_migratepages = 0; |
705 | INIT_LIST_HEAD(&cc.migratepages); | 694 | cc->zone = zone; |
695 | INIT_LIST_HEAD(&cc->freepages); | ||
696 | INIT_LIST_HEAD(&cc->migratepages); | ||
706 | 697 | ||
707 | compact_zone(zone, &cc); | 698 | if (cc->order < 0 || !compaction_deferred(zone)) |
699 | compact_zone(zone, cc); | ||
708 | 700 | ||
709 | VM_BUG_ON(!list_empty(&cc.freepages)); | 701 | VM_BUG_ON(!list_empty(&cc->freepages)); |
710 | VM_BUG_ON(!list_empty(&cc.migratepages)); | 702 | VM_BUG_ON(!list_empty(&cc->migratepages)); |
711 | } | 703 | } |
712 | 704 | ||
713 | return 0; | 705 | return 0; |
714 | } | 706 | } |
715 | 707 | ||
708 | int compact_pgdat(pg_data_t *pgdat, int order) | ||
709 | { | ||
710 | struct compact_control cc = { | ||
711 | .order = order, | ||
712 | .sync = false, | ||
713 | }; | ||
714 | |||
715 | return __compact_pgdat(pgdat, &cc); | ||
716 | } | ||
717 | |||
718 | static int compact_node(int nid) | ||
719 | { | ||
720 | pg_data_t *pgdat; | ||
721 | struct compact_control cc = { | ||
722 | .order = -1, | ||
723 | .sync = true, | ||
724 | }; | ||
725 | |||
726 | if (nid < 0 || nid >= nr_node_ids || !node_online(nid)) | ||
727 | return -EINVAL; | ||
728 | pgdat = NODE_DATA(nid); | ||
729 | |||
730 | return __compact_pgdat(pgdat, &cc); | ||
731 | } | ||
732 | |||
716 | /* Compact all nodes in the system */ | 733 | /* Compact all nodes in the system */ |
717 | static int compact_nodes(void) | 734 | static int compact_nodes(void) |
718 | { | 735 | { |
diff --git a/mm/vmscan.c b/mm/vmscan.c index d7dad2a4e69c..b2b4c4a0ada2 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c | |||
@@ -2919,6 +2919,8 @@ out: | |||
2919 | * and it is potentially going to sleep here. | 2919 | * and it is potentially going to sleep here. |
2920 | */ | 2920 | */ |
2921 | if (order) { | 2921 | if (order) { |
2922 | int zones_need_compaction = 1; | ||
2923 | |||
2922 | for (i = 0; i <= end_zone; i++) { | 2924 | for (i = 0; i <= end_zone; i++) { |
2923 | struct zone *zone = pgdat->node_zones + i; | 2925 | struct zone *zone = pgdat->node_zones + i; |
2924 | 2926 | ||
@@ -2939,9 +2941,17 @@ out: | |||
2939 | goto loop_again; | 2941 | goto loop_again; |
2940 | } | 2942 | } |
2941 | 2943 | ||
2944 | /* Check if the memory needs to be defragmented. */ | ||
2945 | if (zone_watermark_ok(zone, order, | ||
2946 | low_wmark_pages(zone), *classzone_idx, 0)) | ||
2947 | zones_need_compaction = 0; | ||
2948 | |||
2942 | /* If balanced, clear the congested flag */ | 2949 | /* If balanced, clear the congested flag */ |
2943 | zone_clear_flag(zone, ZONE_CONGESTED); | 2950 | zone_clear_flag(zone, ZONE_CONGESTED); |
2944 | } | 2951 | } |
2952 | |||
2953 | if (zones_need_compaction) | ||
2954 | compact_pgdat(pgdat, order); | ||
2945 | } | 2955 | } |
2946 | 2956 | ||
2947 | /* | 2957 | /* |