1#include <kassert.h>
2#include <mem/anon_vma.h>
3#include <mem/avc.h>
4#include <mem/folio.h>
5#include <mem/rmap.h>
6#include <mem/vma_range.h>
7
8static inline pgoff_t va_to_index(const struct vma_range *vr, vaddr_t va) {
9 return vr->pgoff + ((va - vma_range_start(vma_range: vr)) >> PAGE_4K_SHIFT);
10}
11
12/* Walk anon_vma itree, anon_vma_clone() puts a child range's AVC into all
13 * ancestor anon_vma's, so that one tree names every range across fork
14 * hierarchy that can reach this folio's pages */
15void rmap_walk_anon(struct folio *f, rmap_visit_fn visit, void *private) {
16 struct anon_vma *anon_vma = folio_get_anon_vma(f);
17 pgoff_t first = f->index;
18 pgoff_t last = first + folio_nr_pages(f) - 1;
19
20 anon_vma_read_lock(av: anon_vma);
21
22 struct anon_vma_chain *avc;
23 for (avc = anon_vma_itree_first(av: anon_vma, first, last); avc;
24 avc = anon_vma_itree_next(avc, first, last)) {
25 struct vma_range *vr = avc->vma_range;
26 vaddr_t va = vma_range_address(vma_range: vr, index: f->index);
27
28 /* vma_range_address gives folio's base index, for multi-page folio
29 * only partially covered by this range, this can fall outside it,
30 * so we skip them */
31 if (va < vma_range_start(vma_range: vr) || va >= vma_range_end(vma_range: vr))
32 continue;
33
34 visit(vr->mm, va, f, private);
35 }
36
37 anon_vma_unlock(av: anon_vma);
38}
39
40/*
41 * TODO: folio teardown must anon_vm_area_put(folio_get_anon_vma(f)) to balance
42 * this get once folio_free() handles anon folios */
43
44/* First PTE for a new anon folio, now becoming anonymous, owned by the faulting
45 * range's anon_vma, gaining first mapper */
46void folio_add_anon_rmap_new(struct folio *f, struct vma_range *vr,
47 vaddr_t va) {
48 kassert(vr->anon_vma);
49
50 /* TODO: we might consider returning errors for this because
51 * the refcount get might fail? */
52 kassert(anon_vma_get(vr->anon_vma));
53 folio_set_anon(f, av: vr->anon_vma, index: va_to_index(vr, va));
54 folio_set_flag(f, m: FOLIO_FLAG_MAPPED);
55 folio_mapcount_inc(f);
56}
57
58/* New PTE maps already anon folio at `va`, which is already anon */
59void folio_add_anon_rmap(struct folio *f, struct vma_range *vr, vaddr_t va) {
60 kassert(folio_is_anon(f));
61
62 pgoff_t idx = va_to_index(vr, va);
63 kassert(idx >= f->index && idx < f->index + folio_nr_pages(f));
64
65 folio_mapcount_inc(f);
66}
67
68/* e.g. fork: parent and child keep the PTE, folio gains a mapper */
69void folio_add_anon_rmap_shared(struct folio *f, struct vma_range *vr) {
70 (void) vr;
71 kassert(folio_is_anon(f));
72
73 folio_mapcount_inc(f);
74}
75
76void folio_remove_rmap(struct folio *f, struct vma_range *vr) {
77 (void) vr;
78 kassert(folio_is_anon(f));
79
80 folio_mapcount_dec(f); /* true at 0 -> folio is no longer mapped anywhere */
81}
82