1 // SPDX-License-Identifier: GPL-2.0
4 #include "btree_key_cache.h"
5 #include "btree_update.h"
10 #include "subvolume.h"
12 #include <linux/random.h>
14 static int bch2_subvolume_delete(struct btree_trans
*, u32
);
16 static struct bpos
subvolume_children_pos(struct bkey_s_c k
)
18 if (k
.k
->type
!= KEY_TYPE_subvolume
)
21 struct bkey_s_c_subvolume s
= bkey_s_c_to_subvolume(k
);
22 if (!s
.v
->fs_path_parent
)
24 return POS(le32_to_cpu(s
.v
->fs_path_parent
), s
.k
->p
.offset
);
27 static int check_subvol(struct btree_trans
*trans
,
28 struct btree_iter
*iter
,
31 struct bch_fs
*c
= trans
->c
;
32 struct bkey_s_c_subvolume subvol
;
33 struct btree_iter subvol_children_iter
= {};
34 struct bch_snapshot snapshot
;
35 struct printbuf buf
= PRINTBUF
;
39 if (k
.k
->type
!= KEY_TYPE_subvolume
)
42 subvol
= bkey_s_c_to_subvolume(k
);
43 snapid
= le32_to_cpu(subvol
.v
->snapshot
);
44 ret
= bch2_snapshot_lookup(trans
, snapid
, &snapshot
);
46 if (bch2_err_matches(ret
, ENOENT
))
47 bch_err(c
, "subvolume %llu points to nonexistent snapshot %u",
48 k
.k
->p
.offset
, snapid
);
52 if (BCH_SUBVOLUME_UNLINKED(subvol
.v
)) {
53 ret
= bch2_subvolume_delete(trans
, iter
->pos
.offset
);
54 bch_err_msg(c
, ret
, "deleting subvolume %llu", iter
->pos
.offset
);
55 return ret
?: -BCH_ERR_transaction_restart_nested
;
58 if (fsck_err_on(subvol
.k
->p
.offset
== BCACHEFS_ROOT_SUBVOL
&&
59 subvol
.v
->fs_path_parent
,
60 trans
, subvol_root_fs_path_parent_nonzero
,
61 "root subvolume has nonzero fs_path_parent\n%s",
62 (bch2_bkey_val_to_text(&buf
, c
, k
), buf
.buf
))) {
63 struct bkey_i_subvolume
*n
=
64 bch2_bkey_make_mut_typed(trans
, iter
, &subvol
.s_c
, 0, subvolume
);
65 ret
= PTR_ERR_OR_ZERO(n
);
69 n
->v
.fs_path_parent
= 0;
72 if (subvol
.v
->fs_path_parent
) {
73 struct bpos pos
= subvolume_children_pos(k
);
75 struct bkey_s_c subvol_children_k
=
76 bch2_bkey_get_iter(trans
, &subvol_children_iter
,
77 BTREE_ID_subvolume_children
, pos
, 0);
78 ret
= bkey_err(subvol_children_k
);
82 if (fsck_err_on(subvol_children_k
.k
->type
!= KEY_TYPE_set
,
83 trans
, subvol_children_not_set
,
84 "subvolume not set in subvolume_children btree at %llu:%llu\n%s",
85 pos
.inode
, pos
.offset
,
86 (printbuf_reset(&buf
),
87 bch2_bkey_val_to_text(&buf
, c
, k
), buf
.buf
))) {
88 ret
= bch2_btree_bit_mod(trans
, BTREE_ID_subvolume_children
, pos
, true);
94 struct bch_inode_unpacked inode
;
95 ret
= bch2_inode_find_by_inum_nowarn_trans(trans
,
96 (subvol_inum
) { k
.k
->p
.offset
, le64_to_cpu(subvol
.v
->inode
) },
99 if (fsck_err_on(inode
.bi_subvol
!= subvol
.k
->p
.offset
,
100 trans
, subvol_root_wrong_bi_subvol
,
101 "subvol root %llu:%u has wrong bi_subvol field: got %u, should be %llu",
102 inode
.bi_inum
, inode
.bi_snapshot
,
103 inode
.bi_subvol
, subvol
.k
->p
.offset
)) {
104 inode
.bi_subvol
= subvol
.k
->p
.offset
;
105 inode
.bi_snapshot
= le32_to_cpu(subvol
.v
->snapshot
);
106 ret
= __bch2_fsck_write_inode(trans
, &inode
);
110 } else if (bch2_err_matches(ret
, ENOENT
)) {
111 if (fsck_err(trans
, subvol_to_missing_root
,
112 "subvolume %llu points to missing subvolume root %llu:%u",
113 k
.k
->p
.offset
, le64_to_cpu(subvol
.v
->inode
),
114 le32_to_cpu(subvol
.v
->snapshot
))) {
115 ret
= bch2_subvolume_delete(trans
, iter
->pos
.offset
);
116 bch_err_msg(c
, ret
, "deleting subvolume %llu", iter
->pos
.offset
);
117 ret
= ret
?: -BCH_ERR_transaction_restart_nested
;
124 if (!BCH_SUBVOLUME_SNAP(subvol
.v
)) {
125 u32 snapshot_root
= bch2_snapshot_root(c
, le32_to_cpu(subvol
.v
->snapshot
));
127 struct bch_snapshot_tree st
;
130 snapshot_tree
= snapshot_t(c
, snapshot_root
)->tree
;
133 ret
= bch2_snapshot_tree_lookup(trans
, snapshot_tree
, &st
);
135 bch2_fs_inconsistent_on(bch2_err_matches(ret
, ENOENT
), c
,
136 "%s: snapshot tree %u not found", __func__
, snapshot_tree
);
141 if (fsck_err_on(le32_to_cpu(st
.master_subvol
) != subvol
.k
->p
.offset
,
142 trans
, subvol_not_master_and_not_snapshot
,
143 "subvolume %llu is not set as snapshot but is not master subvolume",
145 struct bkey_i_subvolume
*s
=
146 bch2_bkey_make_mut_typed(trans
, iter
, &subvol
.s_c
, 0, subvolume
);
147 ret
= PTR_ERR_OR_ZERO(s
);
151 SET_BCH_SUBVOLUME_SNAP(&s
->v
, true);
156 bch2_trans_iter_exit(trans
, &subvol_children_iter
);
161 int bch2_check_subvols(struct bch_fs
*c
)
163 int ret
= bch2_trans_run(c
,
164 for_each_btree_key_commit(trans
, iter
,
165 BTREE_ID_subvolumes
, POS_MIN
, BTREE_ITER_prefetch
, k
,
166 NULL
, NULL
, BCH_TRANS_COMMIT_no_enospc
,
167 check_subvol(trans
, &iter
, k
)));
172 static int check_subvol_child(struct btree_trans
*trans
,
173 struct btree_iter
*child_iter
,
174 struct bkey_s_c child_k
)
176 struct bch_subvolume s
;
177 int ret
= bch2_bkey_get_val_typed(trans
, BTREE_ID_subvolumes
, POS(0, child_k
.k
->p
.offset
),
179 if (ret
&& !bch2_err_matches(ret
, ENOENT
))
182 if (fsck_err_on(ret
||
183 le32_to_cpu(s
.fs_path_parent
) != child_k
.k
->p
.inode
,
184 trans
, subvol_children_bad
,
185 "incorrect entry in subvolume_children btree %llu:%llu",
186 child_k
.k
->p
.inode
, child_k
.k
->p
.offset
)) {
187 ret
= bch2_btree_delete_at(trans
, child_iter
, 0);
196 int bch2_check_subvol_children(struct bch_fs
*c
)
198 int ret
= bch2_trans_run(c
,
199 for_each_btree_key_commit(trans
, iter
,
200 BTREE_ID_subvolume_children
, POS_MIN
, BTREE_ITER_prefetch
, k
,
201 NULL
, NULL
, BCH_TRANS_COMMIT_no_enospc
,
202 check_subvol_child(trans
, &iter
, k
)));
209 int bch2_subvolume_validate(struct bch_fs
*c
, struct bkey_s_c k
,
210 enum bch_validate_flags flags
)
212 struct bkey_s_c_subvolume subvol
= bkey_s_c_to_subvolume(k
);
215 bkey_fsck_err_on(bkey_lt(k
.k
->p
, SUBVOL_POS_MIN
) ||
216 bkey_gt(k
.k
->p
, SUBVOL_POS_MAX
),
220 bkey_fsck_err_on(!subvol
.v
->snapshot
,
221 c
, subvol_snapshot_bad
,
224 bkey_fsck_err_on(!subvol
.v
->inode
,
231 void bch2_subvolume_to_text(struct printbuf
*out
, struct bch_fs
*c
,
234 struct bkey_s_c_subvolume s
= bkey_s_c_to_subvolume(k
);
236 prt_printf(out
, "root %llu snapshot id %u",
237 le64_to_cpu(s
.v
->inode
),
238 le32_to_cpu(s
.v
->snapshot
));
240 if (bkey_val_bytes(s
.k
) > offsetof(struct bch_subvolume
, creation_parent
)) {
241 prt_printf(out
, " creation_parent %u", le32_to_cpu(s
.v
->creation_parent
));
242 prt_printf(out
, " fs_parent %u", le32_to_cpu(s
.v
->fs_path_parent
));
246 static int subvolume_children_mod(struct btree_trans
*trans
, struct bpos pos
, bool set
)
248 return !bpos_eq(pos
, POS_MIN
)
249 ? bch2_btree_bit_mod(trans
, BTREE_ID_subvolume_children
, pos
, set
)
253 int bch2_subvolume_trigger(struct btree_trans
*trans
,
254 enum btree_id btree_id
, unsigned level
,
255 struct bkey_s_c old
, struct bkey_s
new,
256 enum btree_iter_update_trigger_flags flags
)
258 if (flags
& BTREE_TRIGGER_transactional
) {
259 struct bpos children_pos_old
= subvolume_children_pos(old
);
260 struct bpos children_pos_new
= subvolume_children_pos(new.s_c
);
262 if (!bpos_eq(children_pos_old
, children_pos_new
)) {
263 int ret
= subvolume_children_mod(trans
, children_pos_old
, false) ?:
264 subvolume_children_mod(trans
, children_pos_new
, true);
273 int bch2_subvol_has_children(struct btree_trans
*trans
, u32 subvol
)
275 struct btree_iter iter
;
277 bch2_trans_iter_init(trans
, &iter
, BTREE_ID_subvolume_children
, POS(subvol
, 0), 0);
278 struct bkey_s_c k
= bch2_btree_iter_peek(&iter
);
279 bch2_trans_iter_exit(trans
, &iter
);
281 return bkey_err(k
) ?: k
.k
&& k
.k
->p
.inode
== subvol
282 ? -BCH_ERR_ENOTEMPTY_subvol_not_empty
286 static __always_inline
int
287 bch2_subvolume_get_inlined(struct btree_trans
*trans
, unsigned subvol
,
288 bool inconsistent_if_not_found
,
290 struct bch_subvolume
*s
)
292 int ret
= bch2_bkey_get_val_typed(trans
, BTREE_ID_subvolumes
, POS(0, subvol
),
293 iter_flags
, subvolume
, s
);
294 bch2_fs_inconsistent_on(bch2_err_matches(ret
, ENOENT
) &&
295 inconsistent_if_not_found
,
296 trans
->c
, "missing subvolume %u", subvol
);
300 int bch2_subvolume_get(struct btree_trans
*trans
, unsigned subvol
,
301 bool inconsistent_if_not_found
,
303 struct bch_subvolume
*s
)
305 return bch2_subvolume_get_inlined(trans
, subvol
, inconsistent_if_not_found
, iter_flags
, s
);
308 int bch2_subvol_is_ro_trans(struct btree_trans
*trans
, u32 subvol
)
310 struct bch_subvolume s
;
311 int ret
= bch2_subvolume_get_inlined(trans
, subvol
, true, 0, &s
);
315 if (BCH_SUBVOLUME_RO(&s
))
320 int bch2_subvol_is_ro(struct bch_fs
*c
, u32 subvol
)
322 return bch2_trans_do(c
, bch2_subvol_is_ro_trans(trans
, subvol
));
325 int bch2_snapshot_get_subvol(struct btree_trans
*trans
, u32 snapshot
,
326 struct bch_subvolume
*subvol
)
328 struct bch_snapshot snap
;
330 return bch2_snapshot_lookup(trans
, snapshot
, &snap
) ?:
331 bch2_subvolume_get(trans
, le32_to_cpu(snap
.subvol
), true, 0, subvol
);
334 int __bch2_subvolume_get_snapshot(struct btree_trans
*trans
, u32 subvolid
,
335 u32
*snapid
, bool warn
)
337 struct btree_iter iter
;
338 struct bkey_s_c_subvolume subvol
;
341 subvol
= bch2_bkey_get_iter_typed(trans
, &iter
,
342 BTREE_ID_subvolumes
, POS(0, subvolid
),
343 BTREE_ITER_cached
|BTREE_ITER_with_updates
,
345 ret
= bkey_err(subvol
);
347 bch2_fs_inconsistent_on(warn
&& bch2_err_matches(ret
, ENOENT
), trans
->c
,
348 "missing subvolume %u", subvolid
);
351 *snapid
= le32_to_cpu(subvol
.v
->snapshot
);
352 bch2_trans_iter_exit(trans
, &iter
);
356 int bch2_subvolume_get_snapshot(struct btree_trans
*trans
, u32 subvolid
,
359 return __bch2_subvolume_get_snapshot(trans
, subvolid
, snapid
, true);
362 static int bch2_subvolume_reparent(struct btree_trans
*trans
,
363 struct btree_iter
*iter
,
365 u32 old_parent
, u32 new_parent
)
367 struct bkey_i_subvolume
*s
;
370 if (k
.k
->type
!= KEY_TYPE_subvolume
)
373 if (bkey_val_bytes(k
.k
) > offsetof(struct bch_subvolume
, creation_parent
) &&
374 le32_to_cpu(bkey_s_c_to_subvolume(k
).v
->creation_parent
) != old_parent
)
377 s
= bch2_bkey_make_mut_typed(trans
, iter
, &k
, 0, subvolume
);
378 ret
= PTR_ERR_OR_ZERO(s
);
382 s
->v
.creation_parent
= cpu_to_le32(new_parent
);
387 * Separate from the snapshot tree in the snapshots btree, we record the tree
388 * structure of how snapshot subvolumes were created - the parent subvolume of
389 * each snapshot subvolume.
391 * When a subvolume is deleted, we scan for child subvolumes and reparant them,
392 * to avoid dangling references:
394 static int bch2_subvolumes_reparent(struct btree_trans
*trans
, u32 subvolid_to_delete
)
396 struct bch_subvolume s
;
398 return lockrestart_do(trans
,
399 bch2_subvolume_get(trans
, subvolid_to_delete
, true,
400 BTREE_ITER_cached
, &s
)) ?:
401 for_each_btree_key_commit(trans
, iter
,
402 BTREE_ID_subvolumes
, POS_MIN
, BTREE_ITER_prefetch
, k
,
403 NULL
, NULL
, BCH_TRANS_COMMIT_no_enospc
,
404 bch2_subvolume_reparent(trans
, &iter
, k
,
405 subvolid_to_delete
, le32_to_cpu(s
.creation_parent
)));
409 * Delete subvolume, mark snapshot ID as deleted, queue up snapshot
412 static int __bch2_subvolume_delete(struct btree_trans
*trans
, u32 subvolid
)
414 struct btree_iter iter
;
415 struct bkey_s_c_subvolume subvol
;
419 subvol
= bch2_bkey_get_iter_typed(trans
, &iter
,
420 BTREE_ID_subvolumes
, POS(0, subvolid
),
421 BTREE_ITER_cached
|BTREE_ITER_intent
,
423 ret
= bkey_err(subvol
);
424 bch2_fs_inconsistent_on(bch2_err_matches(ret
, ENOENT
), trans
->c
,
425 "missing subvolume %u", subvolid
);
429 snapid
= le32_to_cpu(subvol
.v
->snapshot
);
431 ret
= bch2_btree_delete_at(trans
, &iter
, 0) ?:
432 bch2_snapshot_node_set_deleted(trans
, snapid
);
433 bch2_trans_iter_exit(trans
, &iter
);
437 static int bch2_subvolume_delete(struct btree_trans
*trans
, u32 subvolid
)
439 return bch2_subvolumes_reparent(trans
, subvolid
) ?:
440 commit_do(trans
, NULL
, NULL
, BCH_TRANS_COMMIT_no_enospc
,
441 __bch2_subvolume_delete(trans
, subvolid
));
444 static void bch2_subvolume_wait_for_pagecache_and_delete(struct work_struct
*work
)
446 struct bch_fs
*c
= container_of(work
, struct bch_fs
,
447 snapshot_wait_for_pagecache_and_delete_work
);
453 mutex_lock(&c
->snapshots_unlinked_lock
);
454 s
= c
->snapshots_unlinked
;
455 darray_init(&c
->snapshots_unlinked
);
456 mutex_unlock(&c
->snapshots_unlinked_lock
);
461 bch2_evict_subvolume_inodes(c
, &s
);
463 for (id
= s
.data
; id
< s
.data
+ s
.nr
; id
++) {
464 ret
= bch2_trans_run(c
, bch2_subvolume_delete(trans
, *id
));
465 bch_err_msg(c
, ret
, "deleting subvolume %u", *id
);
473 bch2_write_ref_put(c
, BCH_WRITE_REF_snapshot_delete_pagecache
);
476 struct subvolume_unlink_hook
{
477 struct btree_trans_commit_hook h
;
481 static int bch2_subvolume_wait_for_pagecache_and_delete_hook(struct btree_trans
*trans
,
482 struct btree_trans_commit_hook
*_h
)
484 struct subvolume_unlink_hook
*h
= container_of(_h
, struct subvolume_unlink_hook
, h
);
485 struct bch_fs
*c
= trans
->c
;
488 mutex_lock(&c
->snapshots_unlinked_lock
);
489 if (!snapshot_list_has_id(&c
->snapshots_unlinked
, h
->subvol
))
490 ret
= snapshot_list_add(c
, &c
->snapshots_unlinked
, h
->subvol
);
491 mutex_unlock(&c
->snapshots_unlinked_lock
);
496 if (!bch2_write_ref_tryget(c
, BCH_WRITE_REF_snapshot_delete_pagecache
))
499 if (!queue_work(c
->write_ref_wq
, &c
->snapshot_wait_for_pagecache_and_delete_work
))
500 bch2_write_ref_put(c
, BCH_WRITE_REF_snapshot_delete_pagecache
);
504 int bch2_subvolume_unlink(struct btree_trans
*trans
, u32 subvolid
)
506 struct btree_iter iter
;
507 struct bkey_i_subvolume
*n
;
508 struct subvolume_unlink_hook
*h
;
511 h
= bch2_trans_kmalloc(trans
, sizeof(*h
));
512 ret
= PTR_ERR_OR_ZERO(h
);
516 h
->h
.fn
= bch2_subvolume_wait_for_pagecache_and_delete_hook
;
517 h
->subvol
= subvolid
;
518 bch2_trans_commit_hook(trans
, &h
->h
);
520 n
= bch2_bkey_get_mut_typed(trans
, &iter
,
521 BTREE_ID_subvolumes
, POS(0, subvolid
),
522 BTREE_ITER_cached
, subvolume
);
523 ret
= PTR_ERR_OR_ZERO(n
);
525 bch2_fs_inconsistent_on(bch2_err_matches(ret
, ENOENT
), trans
->c
,
526 "missing subvolume %u", subvolid
);
530 SET_BCH_SUBVOLUME_UNLINKED(&n
->v
, true);
531 bch2_trans_iter_exit(trans
, &iter
);
535 int bch2_subvolume_create(struct btree_trans
*trans
, u64 inode
,
542 struct bch_fs
*c
= trans
->c
;
543 struct btree_iter dst_iter
, src_iter
= (struct btree_iter
) { NULL
};
544 struct bkey_i_subvolume
*new_subvol
= NULL
;
545 struct bkey_i_subvolume
*src_subvol
= NULL
;
546 u32 parent
= 0, new_nodes
[2], snapshot_subvols
[2];
549 ret
= bch2_bkey_get_empty_slot(trans
, &dst_iter
,
550 BTREE_ID_subvolumes
, POS(0, U32_MAX
));
551 if (ret
== -BCH_ERR_ENOSPC_btree_slot
)
552 ret
= -BCH_ERR_ENOSPC_subvolume_create
;
556 snapshot_subvols
[0] = dst_iter
.pos
.offset
;
557 snapshot_subvols
[1] = src_subvolid
;
560 /* Creating a snapshot: */
562 src_subvol
= bch2_bkey_get_mut_typed(trans
, &src_iter
,
563 BTREE_ID_subvolumes
, POS(0, src_subvolid
),
564 BTREE_ITER_cached
, subvolume
);
565 ret
= PTR_ERR_OR_ZERO(src_subvol
);
567 bch2_fs_inconsistent_on(bch2_err_matches(ret
, ENOENT
), c
,
568 "subvolume %u not found", src_subvolid
);
572 parent
= le32_to_cpu(src_subvol
->v
.snapshot
);
575 ret
= bch2_snapshot_node_create(trans
, parent
, new_nodes
,
577 src_subvolid
? 2 : 1);
582 src_subvol
->v
.snapshot
= cpu_to_le32(new_nodes
[1]);
583 ret
= bch2_trans_update(trans
, &src_iter
, &src_subvol
->k_i
, 0);
588 new_subvol
= bch2_bkey_alloc(trans
, &dst_iter
, 0, subvolume
);
589 ret
= PTR_ERR_OR_ZERO(new_subvol
);
593 new_subvol
->v
.flags
= 0;
594 new_subvol
->v
.snapshot
= cpu_to_le32(new_nodes
[0]);
595 new_subvol
->v
.inode
= cpu_to_le64(inode
);
596 new_subvol
->v
.creation_parent
= cpu_to_le32(src_subvolid
);
597 new_subvol
->v
.fs_path_parent
= cpu_to_le32(parent_subvolid
);
598 new_subvol
->v
.otime
.lo
= cpu_to_le64(bch2_current_time(c
));
599 new_subvol
->v
.otime
.hi
= 0;
601 SET_BCH_SUBVOLUME_RO(&new_subvol
->v
, ro
);
602 SET_BCH_SUBVOLUME_SNAP(&new_subvol
->v
, src_subvolid
!= 0);
604 *new_subvolid
= new_subvol
->k
.p
.offset
;
605 *new_snapshotid
= new_nodes
[0];
607 bch2_trans_iter_exit(trans
, &src_iter
);
608 bch2_trans_iter_exit(trans
, &dst_iter
);
612 int bch2_initialize_subvolumes(struct bch_fs
*c
)
614 struct bkey_i_snapshot_tree root_tree
;
615 struct bkey_i_snapshot root_snapshot
;
616 struct bkey_i_subvolume root_volume
;
619 bkey_snapshot_tree_init(&root_tree
.k_i
);
620 root_tree
.k
.p
.offset
= 1;
621 root_tree
.v
.master_subvol
= cpu_to_le32(1);
622 root_tree
.v
.root_snapshot
= cpu_to_le32(U32_MAX
);
624 bkey_snapshot_init(&root_snapshot
.k_i
);
625 root_snapshot
.k
.p
.offset
= U32_MAX
;
626 root_snapshot
.v
.flags
= 0;
627 root_snapshot
.v
.parent
= 0;
628 root_snapshot
.v
.subvol
= cpu_to_le32(BCACHEFS_ROOT_SUBVOL
);
629 root_snapshot
.v
.tree
= cpu_to_le32(1);
630 SET_BCH_SNAPSHOT_SUBVOL(&root_snapshot
.v
, true);
632 bkey_subvolume_init(&root_volume
.k_i
);
633 root_volume
.k
.p
.offset
= BCACHEFS_ROOT_SUBVOL
;
634 root_volume
.v
.flags
= 0;
635 root_volume
.v
.snapshot
= cpu_to_le32(U32_MAX
);
636 root_volume
.v
.inode
= cpu_to_le64(BCACHEFS_ROOT_INO
);
638 ret
= bch2_btree_insert(c
, BTREE_ID_snapshot_trees
, &root_tree
.k_i
, NULL
, 0, 0) ?:
639 bch2_btree_insert(c
, BTREE_ID_snapshots
, &root_snapshot
.k_i
, NULL
, 0, 0) ?:
640 bch2_btree_insert(c
, BTREE_ID_subvolumes
, &root_volume
.k_i
, NULL
, 0, 0);
645 static int __bch2_fs_upgrade_for_subvolumes(struct btree_trans
*trans
)
647 struct btree_iter iter
;
649 struct bch_inode_unpacked inode
;
652 k
= bch2_bkey_get_iter(trans
, &iter
, BTREE_ID_inodes
,
653 SPOS(0, BCACHEFS_ROOT_INO
, U32_MAX
), 0);
658 if (!bkey_is_inode(k
.k
)) {
659 bch_err(trans
->c
, "root inode not found");
660 ret
= -BCH_ERR_ENOENT_inode
;
664 ret
= bch2_inode_unpack(k
, &inode
);
667 inode
.bi_subvol
= BCACHEFS_ROOT_SUBVOL
;
669 ret
= bch2_inode_write(trans
, &iter
, &inode
);
671 bch2_trans_iter_exit(trans
, &iter
);
675 /* set bi_subvol on root inode */
676 int bch2_fs_upgrade_for_subvolumes(struct bch_fs
*c
)
678 int ret
= bch2_trans_commit_do(c
, NULL
, NULL
, BCH_TRANS_COMMIT_lazy_rw
,
679 __bch2_fs_upgrade_for_subvolumes(trans
));
684 int bch2_fs_subvolumes_init(struct bch_fs
*c
)
686 INIT_WORK(&c
->snapshot_delete_work
, bch2_delete_dead_snapshots_work
);
687 INIT_WORK(&c
->snapshot_wait_for_pagecache_and_delete_work
,
688 bch2_subvolume_wait_for_pagecache_and_delete
);
689 mutex_init(&c
->snapshots_unlinked_lock
);