| 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 | |
| 8 | static 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 */ |
| 15 | void 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 */ |
| 46 | void 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 */ |
| 59 | void 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 */ |
| 69 | void 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 | |
| 76 | void 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 | |