1 // SPDX-License-Identifier: GPL-2.0
3 * DAMON Primitives for The Physical Address Space
5 * Author: SeongJae Park <sj@kernel.org>
8 #define pr_fmt(fmt) "damon-pa: " fmt
10 #include <linux/mmu_notifier.h>
11 #include <linux/page_idle.h>
12 #include <linux/pagemap.h>
13 #include <linux/rmap.h>
14 #include <linux/swap.h>
15 #include <linux/memory-tiers.h>
16 #include <linux/migrate.h>
17 #include <linux/mm_inline.h>
19 #include "../internal.h"
20 #include "ops-common.h"
22 static bool damon_folio_mkold_one(struct folio
*folio
,
23 struct vm_area_struct
*vma
, unsigned long addr
, void *arg
)
25 DEFINE_FOLIO_VMA_WALK(pvmw
, folio
, vma
, addr
, 0);
27 while (page_vma_mapped_walk(&pvmw
)) {
30 damon_ptep_mkold(pvmw
.pte
, vma
, addr
);
32 damon_pmdp_mkold(pvmw
.pmd
, vma
, addr
);
37 static void damon_folio_mkold(struct folio
*folio
)
39 struct rmap_walk_control rwc
= {
40 .rmap_one
= damon_folio_mkold_one
,
41 .anon_lock
= folio_lock_anon_vma_read
,
45 if (!folio_mapped(folio
) || !folio_raw_mapping(folio
)) {
46 folio_set_idle(folio
);
50 need_lock
= !folio_test_anon(folio
) || folio_test_ksm(folio
);
51 if (need_lock
&& !folio_trylock(folio
))
54 rmap_walk(folio
, &rwc
);
61 static void damon_pa_mkold(unsigned long paddr
)
63 struct folio
*folio
= damon_get_folio(PHYS_PFN(paddr
));
68 damon_folio_mkold(folio
);
72 static void __damon_pa_prepare_access_check(struct damon_region
*r
)
74 r
->sampling_addr
= damon_rand(r
->ar
.start
, r
->ar
.end
);
76 damon_pa_mkold(r
->sampling_addr
);
79 static void damon_pa_prepare_access_checks(struct damon_ctx
*ctx
)
81 struct damon_target
*t
;
82 struct damon_region
*r
;
84 damon_for_each_target(t
, ctx
) {
85 damon_for_each_region(r
, t
)
86 __damon_pa_prepare_access_check(r
);
90 static bool damon_folio_young_one(struct folio
*folio
,
91 struct vm_area_struct
*vma
, unsigned long addr
, void *arg
)
94 DEFINE_FOLIO_VMA_WALK(pvmw
, folio
, vma
, addr
, 0);
97 while (page_vma_mapped_walk(&pvmw
)) {
100 *accessed
= pte_young(ptep_get(pvmw
.pte
)) ||
101 !folio_test_idle(folio
) ||
102 mmu_notifier_test_young(vma
->vm_mm
, addr
);
104 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
105 *accessed
= pmd_young(pmdp_get(pvmw
.pmd
)) ||
106 !folio_test_idle(folio
) ||
107 mmu_notifier_test_young(vma
->vm_mm
, addr
);
110 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
113 page_vma_mapped_walk_done(&pvmw
);
118 /* If accessed, stop walking */
119 return *accessed
== false;
122 static bool damon_folio_young(struct folio
*folio
)
124 bool accessed
= false;
125 struct rmap_walk_control rwc
= {
127 .rmap_one
= damon_folio_young_one
,
128 .anon_lock
= folio_lock_anon_vma_read
,
132 if (!folio_mapped(folio
) || !folio_raw_mapping(folio
)) {
133 if (folio_test_idle(folio
))
139 need_lock
= !folio_test_anon(folio
) || folio_test_ksm(folio
);
140 if (need_lock
&& !folio_trylock(folio
))
143 rmap_walk(folio
, &rwc
);
151 static bool damon_pa_young(unsigned long paddr
, unsigned long *folio_sz
)
153 struct folio
*folio
= damon_get_folio(PHYS_PFN(paddr
));
159 accessed
= damon_folio_young(folio
);
160 *folio_sz
= folio_size(folio
);
165 static void __damon_pa_check_access(struct damon_region
*r
,
166 struct damon_attrs
*attrs
)
168 static unsigned long last_addr
;
169 static unsigned long last_folio_sz
= PAGE_SIZE
;
170 static bool last_accessed
;
172 /* If the region is in the last checked page, reuse the result */
173 if (ALIGN_DOWN(last_addr
, last_folio_sz
) ==
174 ALIGN_DOWN(r
->sampling_addr
, last_folio_sz
)) {
175 damon_update_region_access_rate(r
, last_accessed
, attrs
);
179 last_accessed
= damon_pa_young(r
->sampling_addr
, &last_folio_sz
);
180 damon_update_region_access_rate(r
, last_accessed
, attrs
);
182 last_addr
= r
->sampling_addr
;
185 static unsigned int damon_pa_check_accesses(struct damon_ctx
*ctx
)
187 struct damon_target
*t
;
188 struct damon_region
*r
;
189 unsigned int max_nr_accesses
= 0;
191 damon_for_each_target(t
, ctx
) {
192 damon_for_each_region(r
, t
) {
193 __damon_pa_check_access(r
, &ctx
->attrs
);
194 max_nr_accesses
= max(r
->nr_accesses
, max_nr_accesses
);
198 return max_nr_accesses
;
201 static bool __damos_pa_filter_out(struct damos_filter
*filter
,
204 bool matched
= false;
205 struct mem_cgroup
*memcg
;
207 switch (filter
->type
) {
208 case DAMOS_FILTER_TYPE_ANON
:
209 matched
= folio_test_anon(folio
);
211 case DAMOS_FILTER_TYPE_MEMCG
:
213 memcg
= folio_memcg_check(folio
);
217 matched
= filter
->memcg_id
== mem_cgroup_id(memcg
);
220 case DAMOS_FILTER_TYPE_YOUNG
:
221 matched
= damon_folio_young(folio
);
223 damon_folio_mkold(folio
);
229 return matched
== filter
->matching
;
233 * damos_pa_filter_out - Return true if the page should be filtered out.
235 static bool damos_pa_filter_out(struct damos
*scheme
, struct folio
*folio
)
237 struct damos_filter
*filter
;
239 damos_for_each_filter(filter
, scheme
) {
240 if (__damos_pa_filter_out(filter
, folio
))
246 static unsigned long damon_pa_pageout(struct damon_region
*r
, struct damos
*s
)
248 unsigned long addr
, applied
;
249 LIST_HEAD(folio_list
);
250 bool install_young_filter
= true;
251 struct damos_filter
*filter
;
253 /* check access in page level again by default */
254 damos_for_each_filter(filter
, s
) {
255 if (filter
->type
== DAMOS_FILTER_TYPE_YOUNG
) {
256 install_young_filter
= false;
260 if (install_young_filter
) {
261 filter
= damos_new_filter(DAMOS_FILTER_TYPE_YOUNG
, true);
264 damos_add_filter(s
, filter
);
267 for (addr
= r
->ar
.start
; addr
< r
->ar
.end
; addr
+= PAGE_SIZE
) {
268 struct folio
*folio
= damon_get_folio(PHYS_PFN(addr
));
273 if (damos_pa_filter_out(s
, folio
))
276 folio_clear_referenced(folio
);
277 folio_test_clear_young(folio
);
278 if (!folio_isolate_lru(folio
))
280 if (folio_test_unevictable(folio
))
281 folio_putback_lru(folio
);
283 list_add(&folio
->lru
, &folio_list
);
287 if (install_young_filter
)
288 damos_destroy_filter(filter
);
289 applied
= reclaim_pages(&folio_list
);
291 return applied
* PAGE_SIZE
;
294 static inline unsigned long damon_pa_mark_accessed_or_deactivate(
295 struct damon_region
*r
, struct damos
*s
, bool mark_accessed
)
297 unsigned long addr
, applied
= 0;
299 for (addr
= r
->ar
.start
; addr
< r
->ar
.end
; addr
+= PAGE_SIZE
) {
300 struct folio
*folio
= damon_get_folio(PHYS_PFN(addr
));
305 if (damos_pa_filter_out(s
, folio
))
309 folio_mark_accessed(folio
);
311 folio_deactivate(folio
);
312 applied
+= folio_nr_pages(folio
);
316 return applied
* PAGE_SIZE
;
319 static unsigned long damon_pa_mark_accessed(struct damon_region
*r
,
322 return damon_pa_mark_accessed_or_deactivate(r
, s
, true);
325 static unsigned long damon_pa_deactivate_pages(struct damon_region
*r
,
328 return damon_pa_mark_accessed_or_deactivate(r
, s
, false);
331 static unsigned int __damon_pa_migrate_folio_list(
332 struct list_head
*migrate_folios
, struct pglist_data
*pgdat
,
335 unsigned int nr_succeeded
= 0;
336 nodemask_t allowed_mask
= NODE_MASK_NONE
;
337 struct migration_target_control mtc
= {
339 * Allocate from 'node', or fail quickly and quietly.
340 * When this happens, 'page' will likely just be discarded
341 * instead of migrated.
343 .gfp_mask
= (GFP_HIGHUSER_MOVABLE
& ~__GFP_RECLAIM
) |
344 __GFP_NOWARN
| __GFP_NOMEMALLOC
| GFP_NOWAIT
,
346 .nmask
= &allowed_mask
349 if (pgdat
->node_id
== target_nid
|| target_nid
== NUMA_NO_NODE
)
352 if (list_empty(migrate_folios
))
355 /* Migration ignores all cpuset and mempolicy settings */
356 migrate_pages(migrate_folios
, alloc_migrate_folio
, NULL
,
357 (unsigned long)&mtc
, MIGRATE_ASYNC
, MR_DAMON
,
363 static unsigned int damon_pa_migrate_folio_list(struct list_head
*folio_list
,
364 struct pglist_data
*pgdat
,
367 unsigned int nr_migrated
= 0;
369 LIST_HEAD(ret_folios
);
370 LIST_HEAD(migrate_folios
);
372 while (!list_empty(folio_list
)) {
377 folio
= lru_to_folio(folio_list
);
378 list_del(&folio
->lru
);
380 if (!folio_trylock(folio
))
383 /* Relocate its contents to another node. */
384 list_add(&folio
->lru
, &migrate_folios
);
388 list_add(&folio
->lru
, &ret_folios
);
390 /* 'folio_list' is always empty here */
392 /* Migrate folios selected for migration */
393 nr_migrated
+= __damon_pa_migrate_folio_list(
394 &migrate_folios
, pgdat
, target_nid
);
396 * Folios that could not be migrated are still in @migrate_folios. Add
397 * those back on @folio_list
399 if (!list_empty(&migrate_folios
))
400 list_splice_init(&migrate_folios
, folio_list
);
402 try_to_unmap_flush();
404 list_splice(&ret_folios
, folio_list
);
406 while (!list_empty(folio_list
)) {
407 folio
= lru_to_folio(folio_list
);
408 list_del(&folio
->lru
);
409 folio_putback_lru(folio
);
415 static unsigned long damon_pa_migrate_pages(struct list_head
*folio_list
,
419 unsigned long nr_migrated
= 0;
420 LIST_HEAD(node_folio_list
);
421 unsigned int noreclaim_flag
;
423 if (list_empty(folio_list
))
426 noreclaim_flag
= memalloc_noreclaim_save();
428 nid
= folio_nid(lru_to_folio(folio_list
));
430 struct folio
*folio
= lru_to_folio(folio_list
);
432 if (nid
== folio_nid(folio
)) {
433 list_move(&folio
->lru
, &node_folio_list
);
437 nr_migrated
+= damon_pa_migrate_folio_list(&node_folio_list
,
440 nid
= folio_nid(lru_to_folio(folio_list
));
441 } while (!list_empty(folio_list
));
443 nr_migrated
+= damon_pa_migrate_folio_list(&node_folio_list
,
447 memalloc_noreclaim_restore(noreclaim_flag
);
452 static unsigned long damon_pa_migrate(struct damon_region
*r
, struct damos
*s
)
454 unsigned long addr
, applied
;
455 LIST_HEAD(folio_list
);
457 for (addr
= r
->ar
.start
; addr
< r
->ar
.end
; addr
+= PAGE_SIZE
) {
458 struct folio
*folio
= damon_get_folio(PHYS_PFN(addr
));
463 if (damos_pa_filter_out(s
, folio
))
466 if (!folio_isolate_lru(folio
))
468 list_add(&folio
->lru
, &folio_list
);
472 applied
= damon_pa_migrate_pages(&folio_list
, s
->target_nid
);
474 return applied
* PAGE_SIZE
;
478 static unsigned long damon_pa_apply_scheme(struct damon_ctx
*ctx
,
479 struct damon_target
*t
, struct damon_region
*r
,
480 struct damos
*scheme
)
482 switch (scheme
->action
) {
484 return damon_pa_pageout(r
, scheme
);
486 return damon_pa_mark_accessed(r
, scheme
);
487 case DAMOS_LRU_DEPRIO
:
488 return damon_pa_deactivate_pages(r
, scheme
);
489 case DAMOS_MIGRATE_HOT
:
490 case DAMOS_MIGRATE_COLD
:
491 return damon_pa_migrate(r
, scheme
);
495 /* DAMOS actions that not yet supported by 'paddr'. */
501 static int damon_pa_scheme_score(struct damon_ctx
*context
,
502 struct damon_target
*t
, struct damon_region
*r
,
503 struct damos
*scheme
)
505 switch (scheme
->action
) {
507 return damon_cold_score(context
, r
, scheme
);
509 return damon_hot_score(context
, r
, scheme
);
510 case DAMOS_LRU_DEPRIO
:
511 return damon_cold_score(context
, r
, scheme
);
512 case DAMOS_MIGRATE_HOT
:
513 return damon_hot_score(context
, r
, scheme
);
514 case DAMOS_MIGRATE_COLD
:
515 return damon_cold_score(context
, r
, scheme
);
520 return DAMOS_MAX_SCORE
;
523 static int __init
damon_pa_initcall(void)
525 struct damon_operations ops
= {
526 .id
= DAMON_OPS_PADDR
,
529 .prepare_access_checks
= damon_pa_prepare_access_checks
,
530 .check_accesses
= damon_pa_check_accesses
,
531 .reset_aggregated
= NULL
,
532 .target_valid
= NULL
,
534 .apply_scheme
= damon_pa_apply_scheme
,
535 .get_scheme_score
= damon_pa_scheme_score
,
538 return damon_register_ops(&ops
);
541 subsys_initcall(damon_pa_initcall
);