|
@@ -3180,6 +3180,13 @@ out:
|
|
|
return page;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+/*
|
|
|
+ * Maximum number of compaction retries wit a progress before OOM
|
|
|
+ * killer is consider as the only way to move forward.
|
|
|
+ */
|
|
|
+#define MAX_COMPACT_RETRIES 16
|
|
|
+
|
|
|
#ifdef CONFIG_COMPACTION
|
|
|
/* Try memory compaction for high-order allocations before reclaim */
|
|
|
static struct page *
|
|
@@ -3247,14 +3254,60 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
|
|
|
|
|
|
return NULL;
|
|
|
}
|
|
|
+
|
|
|
+static inline bool
|
|
|
+should_compact_retry(unsigned int order, enum compact_result compact_result,
|
|
|
+ enum migrate_mode *migrate_mode,
|
|
|
+ int compaction_retries)
|
|
|
+{
|
|
|
+ if (!order)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * compaction considers all the zone as desperately out of memory
|
|
|
+ * so it doesn't really make much sense to retry except when the
|
|
|
+ * failure could be caused by weak migration mode.
|
|
|
+ */
|
|
|
+ if (compaction_failed(compact_result)) {
|
|
|
+ if (*migrate_mode == MIGRATE_ASYNC) {
|
|
|
+ *migrate_mode = MIGRATE_SYNC_LIGHT;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * !costly allocations are really important and we have to make sure
|
|
|
+ * the compaction wasn't deferred or didn't bail out early due to locks
|
|
|
+ * contention before we go OOM. Still cap the reclaim retry loops with
|
|
|
+ * progress to prevent from looping forever and potential trashing.
|
|
|
+ */
|
|
|
+ if (order <= PAGE_ALLOC_COSTLY_ORDER) {
|
|
|
+ if (compaction_withdrawn(compact_result))
|
|
|
+ return true;
|
|
|
+ if (compaction_retries <= MAX_COMPACT_RETRIES)
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
#else
|
|
|
static inline struct page *
|
|
|
__alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
|
|
|
unsigned int alloc_flags, const struct alloc_context *ac,
|
|
|
enum migrate_mode mode, enum compact_result *compact_result)
|
|
|
{
|
|
|
+ *compact_result = COMPACT_SKIPPED;
|
|
|
return NULL;
|
|
|
}
|
|
|
+
|
|
|
+static inline bool
|
|
|
+should_compact_retry(unsigned int order, enum compact_result compact_result,
|
|
|
+ enum migrate_mode *migrate_mode,
|
|
|
+ int compaction_retries)
|
|
|
+{
|
|
|
+ return false;
|
|
|
+}
|
|
|
#endif /* CONFIG_COMPACTION */
|
|
|
|
|
|
/* Perform direct synchronous page reclaim */
|
|
@@ -3501,6 +3554,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
|
|
|
unsigned long did_some_progress;
|
|
|
enum migrate_mode migration_mode = MIGRATE_ASYNC;
|
|
|
enum compact_result compact_result;
|
|
|
+ int compaction_retries = 0;
|
|
|
int no_progress_loops = 0;
|
|
|
|
|
|
/*
|
|
@@ -3612,13 +3666,8 @@ retry:
|
|
|
goto nopage;
|
|
|
}
|
|
|
|
|
|
- /*
|
|
|
- * It can become very expensive to allocate transparent hugepages at
|
|
|
- * fault, so use asynchronous memory compaction for THP unless it is
|
|
|
- * khugepaged trying to collapse.
|
|
|
- */
|
|
|
- if (!is_thp_gfp_mask(gfp_mask) || (current->flags & PF_KTHREAD))
|
|
|
- migration_mode = MIGRATE_SYNC_LIGHT;
|
|
|
+ if (order && compaction_made_progress(compact_result))
|
|
|
+ compaction_retries++;
|
|
|
|
|
|
/* Try direct reclaim and then allocating */
|
|
|
page = __alloc_pages_direct_reclaim(gfp_mask, order, alloc_flags, ac,
|
|
@@ -3649,6 +3698,17 @@ retry:
|
|
|
no_progress_loops))
|
|
|
goto retry;
|
|
|
|
|
|
+ /*
|
|
|
+ * It doesn't make any sense to retry for the compaction if the order-0
|
|
|
+ * reclaim is not able to make any progress because the current
|
|
|
+ * implementation of the compaction depends on the sufficient amount
|
|
|
+ * of free memory (see __compaction_suitable)
|
|
|
+ */
|
|
|
+ if (did_some_progress > 0 &&
|
|
|
+ should_compact_retry(order, compact_result,
|
|
|
+ &migration_mode, compaction_retries))
|
|
|
+ goto retry;
|
|
|
+
|
|
|
/* Reclaim has failed us, start killing things */
|
|
|
page = __alloc_pages_may_oom(gfp_mask, order, ac, &did_some_progress);
|
|
|
if (page)
|
|
@@ -3662,10 +3722,18 @@ retry:
|
|
|
|
|
|
noretry:
|
|
|
/*
|
|
|
- * High-order allocations do not necessarily loop after
|
|
|
- * direct reclaim and reclaim/compaction depends on compaction
|
|
|
- * being called after reclaim so call directly if necessary
|
|
|
+ * High-order allocations do not necessarily loop after direct reclaim
|
|
|
+ * and reclaim/compaction depends on compaction being called after
|
|
|
+ * reclaim so call directly if necessary.
|
|
|
+ * It can become very expensive to allocate transparent hugepages at
|
|
|
+ * fault, so use asynchronous memory compaction for THP unless it is
|
|
|
+ * khugepaged trying to collapse. All other requests should tolerate
|
|
|
+ * at least light sync migration.
|
|
|
*/
|
|
|
+ if (is_thp_gfp_mask(gfp_mask) && !(current->flags & PF_KTHREAD))
|
|
|
+ migration_mode = MIGRATE_ASYNC;
|
|
|
+ else
|
|
|
+ migration_mode = MIGRATE_SYNC_LIGHT;
|
|
|
page = __alloc_pages_direct_compact(gfp_mask, order, alloc_flags,
|
|
|
ac, migration_mode,
|
|
|
&compact_result);
|