compaction.h 7.1 KB
Newer Older
1
/* SPDX-License-Identifier: GPL-2.0 */
2 3 4
#ifndef _LINUX_COMPACTION_H
#define _LINUX_COMPACTION_H

5 6 7 8 9
/*
 * Determines how hard direct compaction should try to succeed.
 * Lower value means higher priority, analogically to reclaim priority.
 */
enum compact_priority {
10 11
	COMPACT_PRIO_SYNC_FULL,
	MIN_COMPACT_PRIORITY = COMPACT_PRIO_SYNC_FULL,
12
	COMPACT_PRIO_SYNC_LIGHT,
13
	MIN_COMPACT_COSTLY_PRIORITY = COMPACT_PRIO_SYNC_LIGHT,
14 15 16 17 18
	DEF_COMPACT_PRIORITY = COMPACT_PRIO_SYNC_LIGHT,
	COMPACT_PRIO_ASYNC,
	INIT_COMPACT_PRIORITY = COMPACT_PRIO_ASYNC
};

19
/* Return values for compact_zone() and try_to_compact_pages() */
20
/* When adding new states, please adjust include/trace/events/compaction.h */
21
enum compact_result {
22 23
	/* For more detailed tracepoint output - internal to compaction */
	COMPACT_NOT_SUITABLE_ZONE,
24 25 26 27 28
	/*
	 * compaction didn't start as it was not possible or direct reclaim
	 * was more suitable
	 */
	COMPACT_SKIPPED,
29 30
	/* compaction didn't start as it was deferred due to past failures */
	COMPACT_DEFERRED,
31

32 33 34
	/* compaction not active last round */
	COMPACT_INACTIVE = COMPACT_DEFERRED,

35 36
	/* For more detailed tracepoint output - internal to compaction */
	COMPACT_NO_SUITABLE_PAGE,
37 38
	/* compaction should continue to another pageblock */
	COMPACT_CONTINUE,
39

40
	/*
41 42
	 * The full zone was compacted scanned but wasn't successfull to compact
	 * suitable pages.
43
	 */
44
	COMPACT_COMPLETE,
45 46 47 48 49
	/*
	 * direct compaction has scanned part of the zone but wasn't successfull
	 * to compact suitable pages.
	 */
	COMPACT_PARTIAL_SKIPPED,
50 51 52 53

	/* compaction terminated prematurely due to lock contentions */
	COMPACT_CONTENDED,

54
	/*
55 56
	 * direct compaction terminated after concluding that the allocation
	 * should now succeed
57
	 */
58
	COMPACT_SUCCESS,
59
};
60

61 62
struct alloc_context; /* in mm/internal.h */

63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
/*
 * Number of free order-0 pages that should be available above given watermark
 * to make sure compaction has reasonable chance of not running out of free
 * pages that it needs to isolate as migration target during its work.
 */
static inline unsigned long compact_gap(unsigned int order)
{
	/*
	 * Although all the isolations for migration are temporary, compaction
	 * free scanner may have up to 1 << order pages on its list and then
	 * try to split an (order - 1) free page. At that point, a gap of
	 * 1 << order might not be enough, so it's safer to require twice that
	 * amount. Note that the number of pages on the list is also
	 * effectively limited by COMPACT_CLUSTER_MAX, as that's the maximum
	 * that the migrate scanner can have isolated on migrate list, and free
	 * scanner is only invoked when the number of isolated free pages is
	 * lower than that. But it's not worth to complicate the formula here
	 * as a bigger gap for higher orders than strictly necessary can also
	 * improve chances of compaction success.
	 */
	return 2UL << order;
}

86 87 88 89
#ifdef CONFIG_COMPACTION
extern int sysctl_compact_memory;
extern int sysctl_compaction_handler(struct ctl_table *table, int write,
			void __user *buffer, size_t *length, loff_t *ppos);
90 91 92
extern int sysctl_extfrag_threshold;
extern int sysctl_extfrag_handler(struct ctl_table *table, int write,
			void __user *buffer, size_t *length, loff_t *ppos);
93
extern int sysctl_compact_unevictable_allowed;
94 95

extern int fragmentation_index(struct zone *zone, unsigned int order);
96
extern enum compact_result try_to_compact_pages(gfp_t gfp_mask,
97 98
		unsigned int order, unsigned int alloc_flags,
		const struct alloc_context *ac, enum compact_priority prio);
99
extern void reset_isolation_suitable(pg_data_t *pgdat);
100
extern enum compact_result compaction_suitable(struct zone *zone, int order,
101
		unsigned int alloc_flags, int classzone_idx);
102

103 104 105 106 107
extern void defer_compaction(struct zone *zone, int order);
extern bool compaction_deferred(struct zone *zone, int order);
extern void compaction_defer_reset(struct zone *zone, int order,
				bool alloc_success);
extern bool compaction_restarting(struct zone *zone, int order);
108

109 110 111 112 113 114 115 116
/* Compaction has made some progress and retrying makes sense */
static inline bool compaction_made_progress(enum compact_result result)
{
	/*
	 * Even though this might sound confusing this in fact tells us
	 * that the compaction successfully isolated and migrated some
	 * pageblocks.
	 */
117
	if (result == COMPACT_SUCCESS)
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
		return true;

	return false;
}

/* Compaction has failed and it doesn't make much sense to keep retrying. */
static inline bool compaction_failed(enum compact_result result)
{
	/* All zones were scanned completely and still not result. */
	if (result == COMPACT_COMPLETE)
		return true;

	return false;
}

/*
 * Compaction  has backed off for some reason. It might be throttling or
 * lock contention. Retrying is still worthwhile.
 */
static inline bool compaction_withdrawn(enum compact_result result)
{
	/*
	 * Compaction backed off due to watermark checks for order-0
	 * so the regular reclaim has to try harder and reclaim something.
	 */
	if (result == COMPACT_SKIPPED)
		return true;

	/*
	 * If compaction is deferred for high-order allocations, it is
	 * because sync compaction recently failed. If this is the case
	 * and the caller requested a THP allocation, we do not want
	 * to heavily disrupt the system, so we fail the allocation
	 * instead of entering direct reclaim.
	 */
	if (result == COMPACT_DEFERRED)
		return true;

	/*
	 * If compaction in async mode encounters contention or blocks higher
	 * priority task we back off early rather than cause stalls.
	 */
	if (result == COMPACT_CONTENDED)
		return true;

	/*
	 * Page scanners have met but we haven't scanned full zones so this
	 * is a back off in fact.
	 */
	if (result == COMPACT_PARTIAL_SKIPPED)
		return true;

	return false;
}

173 174 175 176

bool compaction_zonelist_suitable(struct alloc_context *ac, int order,
					int alloc_flags);

177 178 179 180
extern int kcompactd_run(int nid);
extern void kcompactd_stop(int nid);
extern void wakeup_kcompactd(pg_data_t *pgdat, int order, int classzone_idx);

181
#else
182 183 184 185
static inline void reset_isolation_suitable(pg_data_t *pgdat)
{
}

186
static inline enum compact_result compaction_suitable(struct zone *zone, int order,
187
					int alloc_flags, int classzone_idx)
188 189 190 191
{
	return COMPACT_SKIPPED;
}

192
static inline void defer_compaction(struct zone *zone, int order)
193 194 195
{
}

196
static inline bool compaction_deferred(struct zone *zone, int order)
197
{
198
	return true;
199 200
}

201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
static inline bool compaction_made_progress(enum compact_result result)
{
	return false;
}

static inline bool compaction_failed(enum compact_result result)
{
	return false;
}

static inline bool compaction_withdrawn(enum compact_result result)
{
	return true;
}

216 217 218 219 220 221 222 223 224 225 226 227
static inline int kcompactd_run(int nid)
{
	return 0;
}
static inline void kcompactd_stop(int nid)
{
}

static inline void wakeup_kcompactd(pg_data_t *pgdat, int order, int classzone_idx)
{
}

228 229
#endif /* CONFIG_COMPACTION */

230
#if defined(CONFIG_COMPACTION) && defined(CONFIG_SYSFS) && defined(CONFIG_NUMA)
231
struct node;
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
extern int compaction_register_node(struct node *node);
extern void compaction_unregister_node(struct node *node);

#else

static inline int compaction_register_node(struct node *node)
{
	return 0;
}

static inline void compaction_unregister_node(struct node *node)
{
}
#endif /* CONFIG_COMPACTION && CONFIG_SYSFS && CONFIG_NUMA */

247
#endif /* _LINUX_COMPACTION_H */