]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/alloc_background.h
Update bcachefs sources to f638850417 bcachefs: bch2_trans_log_msg()
[bcachefs-tools-debian] / libbcachefs / alloc_background.h
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _BCACHEFS_ALLOC_BACKGROUND_H
3 #define _BCACHEFS_ALLOC_BACKGROUND_H
4
5 #include "bcachefs.h"
6 #include "alloc_types.h"
7 #include "buckets.h"
8 #include "debug.h"
9 #include "super.h"
10
11 struct bkey_alloc_unpacked {
12         u64             journal_seq;
13         u64             bucket;
14         u8              dev;
15         u8              gen;
16         u8              oldest_gen;
17         u8              data_type;
18         bool            need_discard:1;
19         bool            need_inc_gen:1;
20 #define x(_name, _bits) u##_bits _name;
21         BCH_ALLOC_FIELDS_V2()
22 #undef  x
23 };
24
25 /* How out of date a pointer gen is allowed to be: */
26 #define BUCKET_GC_GEN_MAX       96U
27
28 static inline u8 alloc_gc_gen(struct bkey_alloc_unpacked a)
29 {
30         return a.gen - a.oldest_gen;
31 }
32
33 enum bucket_state {
34         BUCKET_free,
35         BUCKET_need_gc_gens,
36         BUCKET_need_discard,
37         BUCKET_cached,
38         BUCKET_dirty,
39 };
40
41 extern const char * const bch2_bucket_states[];
42
43 static inline enum bucket_state bucket_state(struct bkey_alloc_unpacked a)
44 {
45         if (a.dirty_sectors || a.stripe)
46                 return BUCKET_dirty;
47         if (a.cached_sectors)
48                 return BUCKET_cached;
49         BUG_ON(a.data_type);
50         if (a.need_discard)
51                 return BUCKET_need_discard;
52         if (alloc_gc_gen(a) >= BUCKET_GC_GEN_MAX)
53                 return BUCKET_need_gc_gens;
54         return BUCKET_free;
55 }
56
57 static inline u64 alloc_lru_idx(struct bkey_alloc_unpacked a)
58 {
59         return bucket_state(a) == BUCKET_cached ? a.read_time : 0;
60 }
61
62 static inline u64 alloc_freespace_genbits(struct bkey_alloc_unpacked a)
63 {
64         return ((u64) alloc_gc_gen(a) >> 4) << 56;
65 }
66
67 static inline struct bpos alloc_freespace_pos(struct bkey_alloc_unpacked a)
68 {
69         return POS(a.dev, a.bucket | alloc_freespace_genbits(a));
70 }
71
72 /* returns true if not equal */
73 static inline bool bkey_alloc_unpacked_cmp(struct bkey_alloc_unpacked l,
74                                            struct bkey_alloc_unpacked r)
75 {
76         return  l.gen != r.gen                  ||
77                 l.oldest_gen != r.oldest_gen    ||
78                 l.data_type != r.data_type
79 #define x(_name, ...)   || l._name != r._name
80         BCH_ALLOC_FIELDS_V2()
81 #undef  x
82         ;
83 }
84
85 struct bkey_alloc_buf {
86         struct bkey_i   k;
87         struct bch_alloc_v3 v;
88
89 #define x(_name,  _bits)                + _bits / 8
90         u8              _pad[0 + BCH_ALLOC_FIELDS_V2()];
91 #undef  x
92 } __attribute__((packed, aligned(8)));
93
94 struct bkey_alloc_unpacked bch2_alloc_unpack(struct bkey_s_c);
95 struct bkey_alloc_buf *bch2_alloc_pack(struct btree_trans *,
96                                        const struct bkey_alloc_unpacked);
97 int bch2_alloc_write(struct btree_trans *, struct btree_iter *,
98                      struct bkey_alloc_unpacked *, unsigned);
99
100 int bch2_bucket_io_time_reset(struct btree_trans *, unsigned, size_t, int);
101
102 #define ALLOC_SCAN_BATCH(ca)            max_t(size_t, 1, (ca)->mi.nbuckets >> 9)
103
104 const char *bch2_alloc_v1_invalid(const struct bch_fs *, struct bkey_s_c);
105 const char *bch2_alloc_v2_invalid(const struct bch_fs *, struct bkey_s_c);
106 const char *bch2_alloc_v3_invalid(const struct bch_fs *, struct bkey_s_c);
107 void bch2_alloc_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
108
109 #define bch2_bkey_ops_alloc (struct bkey_ops) {         \
110         .key_invalid    = bch2_alloc_v1_invalid,        \
111         .val_to_text    = bch2_alloc_to_text,           \
112         .trans_trigger  = bch2_trans_mark_alloc,        \
113         .atomic_trigger = bch2_mark_alloc,              \
114 }
115
116 #define bch2_bkey_ops_alloc_v2 (struct bkey_ops) {      \
117         .key_invalid    = bch2_alloc_v2_invalid,        \
118         .val_to_text    = bch2_alloc_to_text,           \
119         .trans_trigger  = bch2_trans_mark_alloc,        \
120         .atomic_trigger = bch2_mark_alloc,              \
121 }
122
123 #define bch2_bkey_ops_alloc_v3 (struct bkey_ops) {      \
124         .key_invalid    = bch2_alloc_v3_invalid,        \
125         .val_to_text    = bch2_alloc_to_text,           \
126         .trans_trigger  = bch2_trans_mark_alloc,        \
127         .atomic_trigger = bch2_mark_alloc,              \
128 }
129
130 static inline bool bkey_is_alloc(const struct bkey *k)
131 {
132         return  k->type == KEY_TYPE_alloc ||
133                 k->type == KEY_TYPE_alloc_v2 ||
134                 k->type == KEY_TYPE_alloc_v3;
135 }
136
137 int bch2_alloc_read(struct bch_fs *);
138
139 int bch2_trans_mark_alloc(struct btree_trans *, struct bkey_s_c,
140                           struct bkey_i *, unsigned);
141 int bch2_check_alloc_info(struct bch_fs *, bool);
142 void bch2_do_discards(struct bch_fs *);
143
144 static inline bool should_invalidate_buckets(struct bch_dev *ca)
145 {
146         struct bch_dev_usage u = bch2_dev_usage_read(ca);
147
148         return u.d[BCH_DATA_cached].buckets &&
149                 u.buckets_unavailable + u.d[BCH_DATA_cached].buckets <
150                 ca->mi.nbuckets >> 7;
151 }
152
153 void bch2_do_invalidates(struct bch_fs *);
154
155 int bch2_fs_freespace_init(struct bch_fs *);
156
157 void bch2_recalc_capacity(struct bch_fs *);
158
159 void bch2_dev_allocator_remove(struct bch_fs *, struct bch_dev *);
160 void bch2_dev_allocator_add(struct bch_fs *, struct bch_dev *);
161
162 void bch2_fs_allocator_background_init(struct bch_fs *);
163
164 #endif /* _BCACHEFS_ALLOC_BACKGROUND_H */