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