Commit | Line | Data |
---|---|---|
8e877caa KO |
1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | #ifndef _BCACHEFS_SNAPSHOT_H | |
3 | #define _BCACHEFS_SNAPSHOT_H | |
4 | ||
65eaf4e2 | 5 | enum bch_validate_flags; |
8e877caa KO |
6 | |
7 | void bch2_snapshot_tree_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); | |
b65db750 | 8 | int bch2_snapshot_tree_invalid(struct bch_fs *, struct bkey_s_c, |
65eaf4e2 | 9 | enum bch_validate_flags, struct printbuf *); |
8e877caa KO |
10 | |
11 | #define bch2_bkey_ops_snapshot_tree ((struct bkey_ops) { \ | |
12 | .key_invalid = bch2_snapshot_tree_invalid, \ | |
13 | .val_to_text = bch2_snapshot_tree_to_text, \ | |
14 | .min_val_size = 8, \ | |
15 | }) | |
16 | ||
17 | struct bkey_i_snapshot_tree *__bch2_snapshot_tree_create(struct btree_trans *); | |
18 | ||
19 | int bch2_snapshot_tree_lookup(struct btree_trans *, u32, struct bch_snapshot_tree *); | |
20 | ||
21 | void bch2_snapshot_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); | |
b65db750 | 22 | int bch2_snapshot_invalid(struct bch_fs *, struct bkey_s_c, |
65eaf4e2 | 23 | enum bch_validate_flags, struct printbuf *); |
8e877caa | 24 | int bch2_mark_snapshot(struct btree_trans *, enum btree_id, unsigned, |
2d288745 NC |
25 | struct bkey_s_c, struct bkey_s, |
26 | enum btree_iter_update_trigger_flags); | |
8e877caa KO |
27 | |
28 | #define bch2_bkey_ops_snapshot ((struct bkey_ops) { \ | |
29 | .key_invalid = bch2_snapshot_invalid, \ | |
30 | .val_to_text = bch2_snapshot_to_text, \ | |
f0431c5f | 31 | .trigger = bch2_mark_snapshot, \ |
8e877caa KO |
32 | .min_val_size = 24, \ |
33 | }) | |
34 | ||
35 | static inline struct snapshot_t *__snapshot_t(struct snapshot_table *t, u32 id) | |
36 | { | |
63332394 KO |
37 | u32 idx = U32_MAX - id; |
38 | ||
39 | return likely(t && idx < t->nr) | |
40 | ? &t->s[idx] | |
41 | : NULL; | |
8e877caa KO |
42 | } |
43 | ||
44 | static inline const struct snapshot_t *snapshot_t(struct bch_fs *c, u32 id) | |
45 | { | |
46 | return __snapshot_t(rcu_dereference(c->snapshots), id); | |
47 | } | |
48 | ||
49 | static inline u32 bch2_snapshot_tree(struct bch_fs *c, u32 id) | |
50 | { | |
51 | rcu_read_lock(); | |
ec9cc18f KO |
52 | const struct snapshot_t *s = snapshot_t(c, id); |
53 | id = s ? s->tree : 0; | |
8e877caa KO |
54 | rcu_read_unlock(); |
55 | ||
56 | return id; | |
57 | } | |
58 | ||
59 | static inline u32 __bch2_snapshot_parent_early(struct bch_fs *c, u32 id) | |
60 | { | |
ec9cc18f KO |
61 | const struct snapshot_t *s = snapshot_t(c, id); |
62 | return s ? s->parent : 0; | |
8e877caa KO |
63 | } |
64 | ||
65 | static inline u32 bch2_snapshot_parent_early(struct bch_fs *c, u32 id) | |
66 | { | |
67 | rcu_read_lock(); | |
68 | id = __bch2_snapshot_parent_early(c, id); | |
69 | rcu_read_unlock(); | |
70 | ||
71 | return id; | |
72 | } | |
73 | ||
74 | static inline u32 __bch2_snapshot_parent(struct bch_fs *c, u32 id) | |
75 | { | |
ec9cc18f KO |
76 | const struct snapshot_t *s = snapshot_t(c, id); |
77 | if (!s) | |
78 | return 0; | |
8e877caa | 79 | |
ec9cc18f | 80 | u32 parent = s->parent; |
d434c239 | 81 | if (IS_ENABLED(CONFIG_BCACHEFS_DEBUG) && |
ec9cc18f KO |
82 | parent && |
83 | s->depth != snapshot_t(c, parent)->depth + 1) | |
8e877caa KO |
84 | panic("id %u depth=%u parent %u depth=%u\n", |
85 | id, snapshot_t(c, id)->depth, | |
86 | parent, snapshot_t(c, parent)->depth); | |
87 | ||
88 | return parent; | |
8e877caa KO |
89 | } |
90 | ||
91 | static inline u32 bch2_snapshot_parent(struct bch_fs *c, u32 id) | |
92 | { | |
93 | rcu_read_lock(); | |
94 | id = __bch2_snapshot_parent(c, id); | |
95 | rcu_read_unlock(); | |
96 | ||
97 | return id; | |
98 | } | |
99 | ||
100 | static inline u32 bch2_snapshot_nth_parent(struct bch_fs *c, u32 id, u32 n) | |
101 | { | |
102 | rcu_read_lock(); | |
103 | while (n--) | |
104 | id = __bch2_snapshot_parent(c, id); | |
105 | rcu_read_unlock(); | |
106 | ||
107 | return id; | |
108 | } | |
109 | ||
110 | u32 bch2_snapshot_skiplist_get(struct bch_fs *, u32); | |
111 | ||
112 | static inline u32 bch2_snapshot_root(struct bch_fs *c, u32 id) | |
113 | { | |
114 | u32 parent; | |
115 | ||
116 | rcu_read_lock(); | |
117 | while ((parent = __bch2_snapshot_parent(c, id))) | |
118 | id = parent; | |
119 | rcu_read_unlock(); | |
120 | ||
121 | return id; | |
122 | } | |
123 | ||
124 | static inline u32 __bch2_snapshot_equiv(struct bch_fs *c, u32 id) | |
125 | { | |
ec9cc18f KO |
126 | const struct snapshot_t *s = snapshot_t(c, id); |
127 | return s ? s->equiv : 0; | |
8e877caa KO |
128 | } |
129 | ||
130 | static inline u32 bch2_snapshot_equiv(struct bch_fs *c, u32 id) | |
131 | { | |
132 | rcu_read_lock(); | |
133 | id = __bch2_snapshot_equiv(c, id); | |
134 | rcu_read_unlock(); | |
135 | ||
136 | return id; | |
137 | } | |
138 | ||
ec9cc18f | 139 | static inline int bch2_snapshot_is_internal_node(struct bch_fs *c, u32 id) |
8e877caa | 140 | { |
8e877caa | 141 | rcu_read_lock(); |
ec9cc18f KO |
142 | const struct snapshot_t *s = snapshot_t(c, id); |
143 | int ret = s ? s->children[0] : -BCH_ERR_invalid_snapshot_node; | |
8e877caa KO |
144 | rcu_read_unlock(); |
145 | ||
146 | return ret; | |
147 | } | |
148 | ||
ec9cc18f | 149 | static inline int bch2_snapshot_is_leaf(struct bch_fs *c, u32 id) |
8e877caa | 150 | { |
ec9cc18f KO |
151 | int ret = bch2_snapshot_is_internal_node(c, id); |
152 | if (ret < 0) | |
153 | return ret; | |
154 | return !ret; | |
8e877caa KO |
155 | } |
156 | ||
157 | static inline u32 bch2_snapshot_depth(struct bch_fs *c, u32 parent) | |
158 | { | |
159 | u32 depth; | |
160 | ||
161 | rcu_read_lock(); | |
162 | depth = parent ? snapshot_t(c, parent)->depth + 1 : 0; | |
163 | rcu_read_unlock(); | |
164 | ||
165 | return depth; | |
166 | } | |
167 | ||
168 | bool __bch2_snapshot_is_ancestor(struct bch_fs *, u32, u32); | |
169 | ||
170 | static inline bool bch2_snapshot_is_ancestor(struct bch_fs *c, u32 id, u32 ancestor) | |
171 | { | |
172 | return id == ancestor | |
173 | ? true | |
174 | : __bch2_snapshot_is_ancestor(c, id, ancestor); | |
175 | } | |
176 | ||
177 | static inline bool bch2_snapshot_has_children(struct bch_fs *c, u32 id) | |
178 | { | |
179 | const struct snapshot_t *t; | |
180 | bool ret; | |
181 | ||
182 | rcu_read_lock(); | |
183 | t = snapshot_t(c, id); | |
184 | ret = (t->children[0]|t->children[1]) != 0; | |
185 | rcu_read_unlock(); | |
186 | ||
187 | return ret; | |
188 | } | |
189 | ||
190 | static inline bool snapshot_list_has_id(snapshot_id_list *s, u32 id) | |
191 | { | |
8e877caa KO |
192 | darray_for_each(*s, i) |
193 | if (*i == id) | |
194 | return true; | |
195 | return false; | |
196 | } | |
197 | ||
198 | static inline bool snapshot_list_has_ancestor(struct bch_fs *c, snapshot_id_list *s, u32 id) | |
199 | { | |
8e877caa KO |
200 | darray_for_each(*s, i) |
201 | if (bch2_snapshot_is_ancestor(c, id, *i)) | |
202 | return true; | |
203 | return false; | |
204 | } | |
205 | ||
206 | static inline int snapshot_list_add(struct bch_fs *c, snapshot_id_list *s, u32 id) | |
207 | { | |
8e877caa | 208 | BUG_ON(snapshot_list_has_id(s, id)); |
a292be3b | 209 | int ret = darray_push(s, id); |
8e877caa KO |
210 | if (ret) |
211 | bch_err(c, "error reallocating snapshot_id_list (size %zu)", s->size); | |
212 | return ret; | |
213 | } | |
214 | ||
a292be3b KO |
215 | static inline int snapshot_list_add_nodup(struct bch_fs *c, snapshot_id_list *s, u32 id) |
216 | { | |
217 | int ret = snapshot_list_has_id(s, id) | |
218 | ? 0 | |
219 | : darray_push(s, id); | |
220 | if (ret) | |
221 | bch_err(c, "error reallocating snapshot_id_list (size %zu)", s->size); | |
222 | return ret; | |
223 | } | |
224 | ||
225 | static inline int snapshot_list_merge(struct bch_fs *c, snapshot_id_list *dst, snapshot_id_list *src) | |
226 | { | |
227 | darray_for_each(*src, i) { | |
228 | int ret = snapshot_list_add_nodup(c, dst, *i); | |
229 | if (ret) | |
230 | return ret; | |
231 | } | |
232 | ||
233 | return 0; | |
234 | } | |
235 | ||
8e877caa KO |
236 | int bch2_snapshot_lookup(struct btree_trans *trans, u32 id, |
237 | struct bch_snapshot *s); | |
238 | int bch2_snapshot_get_subvol(struct btree_trans *, u32, | |
239 | struct bch_subvolume *); | |
8e877caa KO |
240 | |
241 | /* only exported for tests: */ | |
242 | int bch2_snapshot_node_create(struct btree_trans *, u32, | |
243 | u32 *, u32 *, unsigned); | |
244 | ||
245 | int bch2_check_snapshot_trees(struct bch_fs *); | |
246 | int bch2_check_snapshots(struct bch_fs *); | |
a292be3b | 247 | int bch2_reconstruct_snapshots(struct bch_fs *); |
8e877caa KO |
248 | |
249 | int bch2_snapshot_node_set_deleted(struct btree_trans *, u32); | |
8e877caa KO |
250 | void bch2_delete_dead_snapshots_work(struct work_struct *); |
251 | ||
fa5bed37 KO |
252 | int __bch2_key_has_snapshot_overwrites(struct btree_trans *, enum btree_id, struct bpos); |
253 | ||
254 | static inline int bch2_key_has_snapshot_overwrites(struct btree_trans *trans, | |
255 | enum btree_id id, | |
256 | struct bpos pos) | |
257 | { | |
258 | if (!btree_type_has_snapshots(id) || | |
ec9cc18f | 259 | bch2_snapshot_is_leaf(trans->c, pos.snapshot) > 0) |
fa5bed37 KO |
260 | return 0; |
261 | ||
262 | return __bch2_key_has_snapshot_overwrites(trans, id, pos); | |
263 | } | |
264 | ||
a111901f KO |
265 | int bch2_propagate_key_to_snapshot_leaves(struct btree_trans *, enum btree_id, |
266 | struct bkey_s_c, struct bpos *); | |
267 | ||
8e877caa KO |
268 | int bch2_snapshots_read(struct bch_fs *); |
269 | void bch2_fs_snapshots_exit(struct bch_fs *); | |
270 | ||
271 | #endif /* _BCACHEFS_SNAPSHOT_H */ |