1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _BCACHEFS_SNAPSHOT_H
3 #define _BCACHEFS_SNAPSHOT_H
5 enum bch_validate_flags
;
7 void bch2_snapshot_tree_to_text(struct printbuf
*, struct bch_fs
*, struct bkey_s_c
);
8 int bch2_snapshot_tree_validate(struct bch_fs
*, struct bkey_s_c
,
9 enum bch_validate_flags
);
11 #define bch2_bkey_ops_snapshot_tree ((struct bkey_ops) { \
12 .key_validate = bch2_snapshot_tree_validate, \
13 .val_to_text = bch2_snapshot_tree_to_text, \
17 struct bkey_i_snapshot_tree
*__bch2_snapshot_tree_create(struct btree_trans
*);
19 int bch2_snapshot_tree_lookup(struct btree_trans
*, u32
, struct bch_snapshot_tree
*);
21 void bch2_snapshot_to_text(struct printbuf
*, struct bch_fs
*, struct bkey_s_c
);
22 int bch2_snapshot_validate(struct bch_fs
*, struct bkey_s_c
, enum bch_validate_flags
);
23 int bch2_mark_snapshot(struct btree_trans
*, enum btree_id
, unsigned,
24 struct bkey_s_c
, struct bkey_s
,
25 enum btree_iter_update_trigger_flags
);
27 #define bch2_bkey_ops_snapshot ((struct bkey_ops) { \
28 .key_validate = bch2_snapshot_validate, \
29 .val_to_text = bch2_snapshot_to_text, \
30 .trigger = bch2_mark_snapshot, \
34 static inline struct snapshot_t
*__snapshot_t(struct snapshot_table
*t
, u32 id
)
36 u32 idx
= U32_MAX
- id
;
38 return likely(t
&& idx
< t
->nr
)
43 static inline const struct snapshot_t
*snapshot_t(struct bch_fs
*c
, u32 id
)
45 return __snapshot_t(rcu_dereference(c
->snapshots
), id
);
48 static inline u32
bch2_snapshot_tree(struct bch_fs
*c
, u32 id
)
51 const struct snapshot_t
*s
= snapshot_t(c
, id
);
58 static inline u32
__bch2_snapshot_parent_early(struct bch_fs
*c
, u32 id
)
60 const struct snapshot_t
*s
= snapshot_t(c
, id
);
61 return s
? s
->parent
: 0;
64 static inline u32
bch2_snapshot_parent_early(struct bch_fs
*c
, u32 id
)
67 id
= __bch2_snapshot_parent_early(c
, id
);
73 static inline u32
__bch2_snapshot_parent(struct bch_fs
*c
, u32 id
)
75 const struct snapshot_t
*s
= snapshot_t(c
, id
);
79 u32 parent
= s
->parent
;
80 if (IS_ENABLED(CONFIG_BCACHEFS_DEBUG
) &&
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
);
90 static inline u32
bch2_snapshot_parent(struct bch_fs
*c
, u32 id
)
93 id
= __bch2_snapshot_parent(c
, id
);
99 static inline u32
bch2_snapshot_nth_parent(struct bch_fs
*c
, u32 id
, u32 n
)
103 id
= __bch2_snapshot_parent(c
, id
);
109 u32
bch2_snapshot_skiplist_get(struct bch_fs
*, u32
);
111 static inline u32
bch2_snapshot_root(struct bch_fs
*c
, u32 id
)
116 while ((parent
= __bch2_snapshot_parent(c
, id
)))
123 static inline u32
__bch2_snapshot_equiv(struct bch_fs
*c
, u32 id
)
125 const struct snapshot_t
*s
= snapshot_t(c
, id
);
126 return s
? s
->equiv
: 0;
129 static inline u32
bch2_snapshot_equiv(struct bch_fs
*c
, u32 id
)
132 id
= __bch2_snapshot_equiv(c
, id
);
138 static inline int bch2_snapshot_is_internal_node(struct bch_fs
*c
, u32 id
)
141 const struct snapshot_t
*s
= snapshot_t(c
, id
);
142 int ret
= s
? s
->children
[0] : -BCH_ERR_invalid_snapshot_node
;
148 static inline int bch2_snapshot_is_leaf(struct bch_fs
*c
, u32 id
)
150 int ret
= bch2_snapshot_is_internal_node(c
, id
);
156 static inline u32
bch2_snapshot_depth(struct bch_fs
*c
, u32 parent
)
161 depth
= parent
? snapshot_t(c
, parent
)->depth
+ 1 : 0;
167 bool __bch2_snapshot_is_ancestor(struct bch_fs
*, u32
, u32
);
169 static inline bool bch2_snapshot_is_ancestor(struct bch_fs
*c
, u32 id
, u32 ancestor
)
171 return id
== ancestor
173 : __bch2_snapshot_is_ancestor(c
, id
, ancestor
);
176 static inline bool bch2_snapshot_has_children(struct bch_fs
*c
, u32 id
)
179 const struct snapshot_t
*t
= snapshot_t(c
, id
);
180 bool ret
= t
&& (t
->children
[0]|t
->children
[1]) != 0;
186 static inline bool snapshot_list_has_id(snapshot_id_list
*s
, u32 id
)
188 darray_for_each(*s
, i
)
194 static inline bool snapshot_list_has_ancestor(struct bch_fs
*c
, snapshot_id_list
*s
, u32 id
)
196 darray_for_each(*s
, i
)
197 if (bch2_snapshot_is_ancestor(c
, id
, *i
))
202 static inline int snapshot_list_add(struct bch_fs
*c
, snapshot_id_list
*s
, u32 id
)
204 BUG_ON(snapshot_list_has_id(s
, id
));
205 int ret
= darray_push(s
, id
);
207 bch_err(c
, "error reallocating snapshot_id_list (size %zu)", s
->size
);
211 static inline int snapshot_list_add_nodup(struct bch_fs
*c
, snapshot_id_list
*s
, u32 id
)
213 int ret
= snapshot_list_has_id(s
, id
)
215 : darray_push(s
, id
);
217 bch_err(c
, "error reallocating snapshot_id_list (size %zu)", s
->size
);
221 static inline int snapshot_list_merge(struct bch_fs
*c
, snapshot_id_list
*dst
, snapshot_id_list
*src
)
223 darray_for_each(*src
, i
) {
224 int ret
= snapshot_list_add_nodup(c
, dst
, *i
);
232 int bch2_snapshot_lookup(struct btree_trans
*trans
, u32 id
,
233 struct bch_snapshot
*s
);
234 int bch2_snapshot_get_subvol(struct btree_trans
*, u32
,
235 struct bch_subvolume
*);
237 /* only exported for tests: */
238 int bch2_snapshot_node_create(struct btree_trans
*, u32
,
239 u32
*, u32
*, unsigned);
241 int bch2_check_snapshot_trees(struct bch_fs
*);
242 int bch2_check_snapshots(struct bch_fs
*);
243 int bch2_reconstruct_snapshots(struct bch_fs
*);
244 int bch2_check_key_has_snapshot(struct btree_trans
*, struct btree_iter
*, struct bkey_s_c
);
246 int bch2_snapshot_node_set_deleted(struct btree_trans
*, u32
);
247 void bch2_delete_dead_snapshots_work(struct work_struct
*);
249 int __bch2_key_has_snapshot_overwrites(struct btree_trans
*, enum btree_id
, struct bpos
);
251 static inline int bch2_key_has_snapshot_overwrites(struct btree_trans
*trans
,
255 if (!btree_type_has_snapshots(id
) ||
256 bch2_snapshot_is_leaf(trans
->c
, pos
.snapshot
) > 0)
259 return __bch2_key_has_snapshot_overwrites(trans
, id
, pos
);
262 int bch2_snapshots_read(struct bch_fs
*);
263 void bch2_fs_snapshots_exit(struct bch_fs
*);
265 #endif /* _BCACHEFS_SNAPSHOT_H */