]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcache/btree_gc.h
0607187f6081dfe457b2d6fa9e816bc7a3e67671
[bcachefs-tools-debian] / libbcache / btree_gc.h
1 #ifndef _BCACHE_GC_H
2 #define _BCACHE_GC_H
3
4 #include "btree_types.h"
5
6 enum bkey_type;
7
8 void bch_coalesce(struct cache_set *);
9 void bch_gc(struct cache_set *);
10 void bch_gc_thread_stop(struct cache_set *);
11 int bch_gc_thread_start(struct cache_set *);
12 int bch_initial_gc(struct cache_set *, struct list_head *);
13 u8 bch_btree_key_recalc_oldest_gen(struct cache_set *, struct bkey_s_c);
14 u8 bch_btree_mark_key_initial(struct cache_set *, enum bkey_type,
15                                 struct bkey_s_c);
16
17 /*
18  * For concurrent mark and sweep (with other index updates), we define a total
19  * ordering of _all_ references GC walks:
20  *
21  * Note that some references will have the same GC position as others - e.g.
22  * everything within the same btree node; in those cases we're relying on
23  * whatever locking exists for where those references live, i.e. the write lock
24  * on a btree node.
25  *
26  * That locking is also required to ensure GC doesn't pass the updater in
27  * between the updater adding/removing the reference and updating the GC marks;
28  * without that, we would at best double count sometimes.
29  *
30  * That part is important - whenever calling bch_mark_pointers(), a lock _must_
31  * be held that prevents GC from passing the position the updater is at.
32  *
33  * (What about the start of gc, when we're clearing all the marks? GC clears the
34  * mark with the gc pos seqlock held, and bch_mark_bucket checks against the gc
35  * position inside its cmpxchg loop, so crap magically works).
36  */
37
38 /* Position of (the start of) a gc phase: */
39 static inline struct gc_pos gc_phase(enum gc_phase phase)
40 {
41         return (struct gc_pos) {
42                 .phase  = phase,
43                 .pos    = POS_MIN,
44                 .level  = 0,
45         };
46 }
47
48 #define GC_POS_MIN      gc_phase(0)
49
50 static inline int gc_pos_cmp(struct gc_pos l, struct gc_pos r)
51 {
52         if (l.phase != r.phase)
53                 return l.phase < r.phase ? -1 : 1;
54         if (bkey_cmp(l.pos, r.pos))
55                 return bkey_cmp(l.pos, r.pos);
56         if (l.level != r.level)
57                 return l.level < r.level ? -1 : 1;
58         return 0;
59 }
60
61 /*
62  * GC position of the pointers within a btree node: note, _not_ for &b->key
63  * itself, that lives in the parent node:
64  */
65 static inline struct gc_pos gc_pos_btree_node(struct btree *b)
66 {
67         return (struct gc_pos) {
68                 .phase  = b->btree_id,
69                 .pos    = b->key.k.p,
70                 .level  = b->level,
71         };
72 }
73
74 /*
75  * GC position of the pointer to a btree root: we don't use
76  * gc_pos_pointer_to_btree_node() here to avoid a potential race with
77  * btree_split() increasing the tree depth - the new root will have level > the
78  * old root and thus have a greater gc position than the old root, but that
79  * would be incorrect since once gc has marked the root it's not coming back.
80  */
81 static inline struct gc_pos gc_pos_btree_root(enum btree_id id)
82 {
83         return (struct gc_pos) {
84                 .phase  = (int) id,
85                 .pos    = POS_MAX,
86                 .level  = U8_MAX,
87         };
88 }
89
90 static inline bool gc_will_visit(struct cache_set *c, struct gc_pos pos)
91 {
92         unsigned seq;
93         bool ret;
94
95         do {
96                 seq = read_seqcount_begin(&c->gc_pos_lock);
97                 ret = gc_pos_cmp(c->gc_pos, pos) < 0;
98         } while (read_seqcount_retry(&c->gc_pos_lock, seq));
99
100         return ret;
101 }
102
103 #endif