]> git.karo-electronics.de Git - linux-beck.git/blobdiff - mm/compaction.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/egtvedt...
[linux-beck.git] / mm / compaction.c
index b6ede459c1bbf5a70ebeadf0803ecc5784fa82cb..b68736c8a1ce0d5c74bd8ebfa78b502c5be37cf6 100644 (file)
@@ -124,6 +124,77 @@ static struct page *pageblock_pfn_to_page(unsigned long start_pfn,
 }
 
 #ifdef CONFIG_COMPACTION
+
+/* Do not skip compaction more than 64 times */
+#define COMPACT_MAX_DEFER_SHIFT 6
+
+/*
+ * Compaction is deferred when compaction fails to result in a page
+ * allocation success. 1 << compact_defer_limit compactions are skipped up
+ * to a limit of 1 << COMPACT_MAX_DEFER_SHIFT
+ */
+void defer_compaction(struct zone *zone, int order)
+{
+       zone->compact_considered = 0;
+       zone->compact_defer_shift++;
+
+       if (order < zone->compact_order_failed)
+               zone->compact_order_failed = order;
+
+       if (zone->compact_defer_shift > COMPACT_MAX_DEFER_SHIFT)
+               zone->compact_defer_shift = COMPACT_MAX_DEFER_SHIFT;
+
+       trace_mm_compaction_defer_compaction(zone, order);
+}
+
+/* Returns true if compaction should be skipped this time */
+bool compaction_deferred(struct zone *zone, int order)
+{
+       unsigned long defer_limit = 1UL << zone->compact_defer_shift;
+
+       if (order < zone->compact_order_failed)
+               return false;
+
+       /* Avoid possible overflow */
+       if (++zone->compact_considered > defer_limit)
+               zone->compact_considered = defer_limit;
+
+       if (zone->compact_considered >= defer_limit)
+               return false;
+
+       trace_mm_compaction_deferred(zone, order);
+
+       return true;
+}
+
+/*
+ * Update defer tracking counters after successful compaction of given order,
+ * which means an allocation either succeeded (alloc_success == true) or is
+ * expected to succeed.
+ */
+void compaction_defer_reset(struct zone *zone, int order,
+               bool alloc_success)
+{
+       if (alloc_success) {
+               zone->compact_considered = 0;
+               zone->compact_defer_shift = 0;
+       }
+       if (order >= zone->compact_order_failed)
+               zone->compact_order_failed = order + 1;
+
+       trace_mm_compaction_defer_reset(zone, order);
+}
+
+/* Returns true if restarting compaction after many failures */
+bool compaction_restarting(struct zone *zone, int order)
+{
+       if (order < zone->compact_order_failed)
+               return false;
+
+       return zone->compact_defer_shift == COMPACT_MAX_DEFER_SHIFT &&
+               zone->compact_considered >= 1UL << zone->compact_defer_shift;
+}
+
 /* Returns true if the pageblock should be scanned for pages to isolate. */
 static inline bool isolation_suitable(struct compact_control *cc,
                                        struct page *page)