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