1/* @title: Anonymous Virtual Memory Area */
2#pragma once
3#include <compiler/wrapper.h>
4#include <err.h>
5#include <structures/rbit.h>
6#include <sync/rwlock.h>
7#include <types/refcount.h>
8#include <types/types.h>
9
10/* LOCK ORDERING:
11 *
12 * mmap_lock
13 * └─ anon_vma->root->lock
14 * └─ folio_lock
15 */
16
17struct vma_range;
18
19struct anon_vma {
20 struct rbit tree; /* AVCs, keyed in OBJECT-SPACE [pgoff, pgoff+npages) */
21 struct anon_vma *root; /* oldest ancestor, the lock is here */
22 struct anon_vma *parent; /* immediate ancestor in fork hierarchy */
23 struct rwlock lock; /* acquire via root */
24 refcount_t refcount; /* # AVCs + folios referencing this object */
25};
26
27struct anon_vma *anon_vma_alloc(void) cw_alloc();
28void anon_vma_free(struct anon_vma *av); /* refcount==0 only */
29enum err anon_vma_fork(struct vma_range *child, struct vma_range *parent);
30
31/* root->lock */
32static inline void anon_vma_read_lock(struct anon_vma *av)
33 TSA_ACQUIRES(&av->root->lock) {
34 rw_read_lock(&av->root->lock);
35}
36
37static inline void anon_vma_unlock(struct anon_vma *av)
38 TSA_RELEASES(&av->root->lock) {
39 rw_unlock(&av->root->lock);
40}
41
42static inline void anon_vma_write_lock(struct anon_vma *av)
43 TSA_ACQUIRES(&av->root->lock) {
44 rw_write_lock(&av->root->lock);
45}
46
47enum err anon_vma_clone(struct vma_range *dst, struct vma_range *src);
48
49struct anon_vma_chain *anon_vma_itree_first(struct anon_vma *av, pgoff_t first,
50 pgoff_t last);
51struct anon_vma_chain *anon_vma_itree_next(struct anon_vma_chain *avc,
52 pgoff_t first, pgoff_t last);
53
54/* teardown: unlink all AVCs on this vma_range, drop anon_vma refs */
55void vma_range_unlink_anon_vmas(struct vma_range *vma_range);
56
57static inline bool anon_vma_is_root(const struct anon_vma *av) {
58 return av->root == av;
59}
60
61static inline bool anon_vma_getref(struct anon_vma *av) {
62 return refcount_inc_not_zero(rc: &av->refcount);
63}
64
65/* Drop ref: When forked anon_vma dies it releases its root pin, allowing
66 * the putref to go up the hierarchy, but it's bounded, as root is its own
67 * root */
68static inline void anon_vma_putref(struct anon_vma *av) {
69 while (av) {
70 struct anon_vma *root = av->root;
71 if (!refcount_dec_and_test(rc: &av->refcount))
72 return;
73 anon_vma_free(av);
74 av = (root != av) ? root : NULL;
75 }
76}
77