Skip to content

Commit cc05329

Browse files
author
Kent Overstreet
committed
bcachefs: Subvolume reconstruction
We can now recreate missing subvolumes from dirents and/or inodes. Signed-off-by: Kent Overstreet <[email protected]>
1 parent 4c02e63 commit cc05329

File tree

1 file changed

+148
-19
lines changed

1 file changed

+148
-19
lines changed

fs/bcachefs/fsck.c

Lines changed: 148 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,7 @@ static int subvol_lookup(struct btree_trans *trans, u32 subvol,
6363
u32 *snapshot, u64 *inum)
6464
{
6565
struct bch_subvolume s;
66-
int ret;
67-
68-
ret = bch2_subvolume_get(trans, subvol, false, 0, &s);
66+
int ret = bch2_subvolume_get(trans, subvol, false, 0, &s);
6967

7068
*snapshot = le32_to_cpu(s.snapshot);
7169
*inum = le64_to_cpu(s.inode);
@@ -170,7 +168,8 @@ static int __remove_dirent(struct btree_trans *trans, struct bpos pos)
170168

171169
/* Get lost+found, create if it doesn't exist: */
172170
static int lookup_lostfound(struct btree_trans *trans, u32 snapshot,
173-
struct bch_inode_unpacked *lostfound)
171+
struct bch_inode_unpacked *lostfound,
172+
u64 reattaching_inum)
174173
{
175174
struct bch_fs *c = trans->c;
176175
struct qstr lostfound_str = QSTR("lost+found");
@@ -185,19 +184,36 @@ static int lookup_lostfound(struct btree_trans *trans, u32 snapshot,
185184
return ret;
186185

187186
subvol_inum root_inum = { .subvol = le32_to_cpu(st.master_subvol) };
188-
u32 subvol_snapshot;
189187

190-
ret = subvol_lookup(trans, le32_to_cpu(st.master_subvol),
191-
&subvol_snapshot, &root_inum.inum);
192-
bch_err_msg(c, ret, "looking up root subvol");
188+
struct bch_subvolume subvol;
189+
ret = bch2_subvolume_get(trans, le32_to_cpu(st.master_subvol),
190+
false, 0, &subvol);
191+
bch_err_msg(c, ret, "looking up root subvol %u for snapshot %u",
192+
le32_to_cpu(st.master_subvol), snapshot);
193193
if (ret)
194194
return ret;
195195

196+
if (!subvol.inode) {
197+
struct btree_iter iter;
198+
struct bkey_i_subvolume *subvol = bch2_bkey_get_mut_typed(trans, &iter,
199+
BTREE_ID_subvolumes, POS(0, le32_to_cpu(st.master_subvol)),
200+
0, subvolume);
201+
ret = PTR_ERR_OR_ZERO(subvol);
202+
if (ret)
203+
return ret;
204+
205+
subvol->v.inode = cpu_to_le64(reattaching_inum);
206+
bch2_trans_iter_exit(trans, &iter);
207+
}
208+
209+
root_inum.inum = le64_to_cpu(subvol.inode);
210+
196211
struct bch_inode_unpacked root_inode;
197212
struct bch_hash_info root_hash_info;
198213
u32 root_inode_snapshot = snapshot;
199214
ret = lookup_inode(trans, root_inum.inum, &root_inode, &root_inode_snapshot);
200-
bch_err_msg(c, ret, "looking up root inode");
215+
bch_err_msg(c, ret, "looking up root inode %llu for subvol %u",
216+
root_inum.inum, le32_to_cpu(st.master_subvol));
201217
if (ret)
202218
return ret;
203219

@@ -293,7 +309,7 @@ static int reattach_inode(struct btree_trans *trans,
293309
snprintf(name_buf, sizeof(name_buf), "%llu", inode->bi_inum);
294310
}
295311

296-
ret = lookup_lostfound(trans, dirent_snapshot, &lostfound);
312+
ret = lookup_lostfound(trans, dirent_snapshot, &lostfound, inode->bi_inum);
297313
if (ret)
298314
return ret;
299315

@@ -364,6 +380,85 @@ static int reattach_subvol(struct btree_trans *trans, struct bkey_s_c_subvolume
364380
return ret;
365381
}
366382

383+
static int reconstruct_subvol(struct btree_trans *trans, u32 snapshotid, u32 subvolid, u64 inum)
384+
{
385+
struct bch_fs *c = trans->c;
386+
387+
if (!bch2_snapshot_is_leaf(c, snapshotid)) {
388+
bch_err(c, "need to reconstruct subvol, but have interior node snapshot");
389+
return -BCH_ERR_fsck_repair_unimplemented;
390+
}
391+
392+
/*
393+
* If inum isn't set, that means we're being called from check_dirents,
394+
* not check_inodes - the root of this subvolume doesn't exist or we
395+
* would have found it there:
396+
*/
397+
if (!inum) {
398+
struct btree_iter inode_iter = {};
399+
struct bch_inode_unpacked new_inode;
400+
u64 cpu = raw_smp_processor_id();
401+
402+
bch2_inode_init_early(c, &new_inode);
403+
bch2_inode_init_late(&new_inode, bch2_current_time(c), 0, 0, S_IFDIR|0755, 0, NULL);
404+
405+
new_inode.bi_subvol = subvolid;
406+
407+
int ret = bch2_inode_create(trans, &inode_iter, &new_inode, snapshotid, cpu) ?:
408+
bch2_btree_iter_traverse(&inode_iter) ?:
409+
bch2_inode_write(trans, &inode_iter, &new_inode);
410+
bch2_trans_iter_exit(trans, &inode_iter);
411+
if (ret)
412+
return ret;
413+
414+
inum = new_inode.bi_inum;
415+
}
416+
417+
bch_info(c, "reconstructing subvol %u with root inode %llu", subvolid, inum);
418+
419+
struct bkey_i_subvolume *new_subvol = bch2_trans_kmalloc(trans, sizeof(*new_subvol));
420+
int ret = PTR_ERR_OR_ZERO(new_subvol);
421+
if (ret)
422+
return ret;
423+
424+
bkey_subvolume_init(&new_subvol->k_i);
425+
new_subvol->k.p.offset = subvolid;
426+
new_subvol->v.snapshot = cpu_to_le32(snapshotid);
427+
new_subvol->v.inode = cpu_to_le64(inum);
428+
ret = bch2_btree_insert_trans(trans, BTREE_ID_subvolumes, &new_subvol->k_i, 0);
429+
if (ret)
430+
return ret;
431+
432+
struct btree_iter iter;
433+
struct bkey_i_snapshot *s = bch2_bkey_get_mut_typed(trans, &iter,
434+
BTREE_ID_snapshots, POS(0, snapshotid),
435+
0, snapshot);
436+
ret = PTR_ERR_OR_ZERO(s);
437+
bch_err_msg(c, ret, "getting snapshot %u", snapshotid);
438+
if (ret)
439+
return ret;
440+
441+
u32 snapshot_tree = le32_to_cpu(s->v.tree);
442+
443+
s->v.subvol = cpu_to_le32(subvolid);
444+
SET_BCH_SNAPSHOT_SUBVOL(&s->v, true);
445+
bch2_trans_iter_exit(trans, &iter);
446+
447+
struct bkey_i_snapshot_tree *st = bch2_bkey_get_mut_typed(trans, &iter,
448+
BTREE_ID_snapshot_trees, POS(0, snapshot_tree),
449+
0, snapshot_tree);
450+
ret = PTR_ERR_OR_ZERO(st);
451+
bch_err_msg(c, ret, "getting snapshot tree %u", snapshot_tree);
452+
if (ret)
453+
return ret;
454+
455+
if (!st->v.master_subvol)
456+
st->v.master_subvol = cpu_to_le32(subvolid);
457+
458+
bch2_trans_iter_exit(trans, &iter);
459+
return 0;
460+
}
461+
367462
struct snapshots_seen_entry {
368463
u32 id;
369464
u32 equiv;
@@ -1065,6 +1160,11 @@ static int check_inode(struct btree_trans *trans,
10651160
if (ret && !bch2_err_matches(ret, ENOENT))
10661161
goto err;
10671162

1163+
if (ret && (c->sb.btrees_lost_data & BIT_ULL(BTREE_ID_subvolumes))) {
1164+
ret = reconstruct_subvol(trans, k.k->p.snapshot, u.bi_subvol, u.bi_inum);
1165+
goto do_update;
1166+
}
1167+
10681168
if (fsck_err_on(ret,
10691169
c, inode_bi_subvol_missing,
10701170
"inode %llu:%u bi_subvol points to missing subvolume %u",
@@ -1082,7 +1182,7 @@ static int check_inode(struct btree_trans *trans,
10821182
do_update = true;
10831183
}
10841184
}
1085-
1185+
do_update:
10861186
if (do_update) {
10871187
ret = __bch2_fsck_write_inode(trans, &u, iter->pos.snapshot);
10881188
bch_err_msg(c, ret, "in fsck updating inode");
@@ -1785,6 +1885,7 @@ static int check_dirent_to_subvol(struct btree_trans *trans, struct btree_iter *
17851885
u32 parent_subvol = le32_to_cpu(d.v->d_parent_subvol);
17861886
u32 target_subvol = le32_to_cpu(d.v->d_child_subvol);
17871887
u32 parent_snapshot;
1888+
u32 new_parent_subvol = 0;
17881889
u64 parent_inum;
17891890
struct printbuf buf = PRINTBUF;
17901891
int ret = 0;
@@ -1793,6 +1894,27 @@ static int check_dirent_to_subvol(struct btree_trans *trans, struct btree_iter *
17931894
if (ret && !bch2_err_matches(ret, ENOENT))
17941895
return ret;
17951896

1897+
if (ret ||
1898+
(!ret && !bch2_snapshot_is_ancestor(c, parent_snapshot, d.k->p.snapshot))) {
1899+
int ret2 = find_snapshot_subvol(trans, d.k->p.snapshot, &new_parent_subvol);
1900+
if (ret2 && !bch2_err_matches(ret, ENOENT))
1901+
return ret2;
1902+
}
1903+
1904+
if (ret &&
1905+
!new_parent_subvol &&
1906+
(c->sb.btrees_lost_data & BIT_ULL(BTREE_ID_subvolumes))) {
1907+
/*
1908+
* Couldn't find a subvol for dirent's snapshot - but we lost
1909+
* subvols, so we need to reconstruct:
1910+
*/
1911+
ret = reconstruct_subvol(trans, d.k->p.snapshot, parent_subvol, 0);
1912+
if (ret)
1913+
return ret;
1914+
1915+
parent_snapshot = d.k->p.snapshot;
1916+
}
1917+
17961918
if (fsck_err_on(ret, c, dirent_to_missing_parent_subvol,
17971919
"dirent parent_subvol points to missing subvolume\n%s",
17981920
(bch2_bkey_val_to_text(&buf, c, d.s_c), buf.buf)) ||
@@ -1801,10 +1923,10 @@ static int check_dirent_to_subvol(struct btree_trans *trans, struct btree_iter *
18011923
"dirent not visible in parent_subvol (not an ancestor of subvol snap %u)\n%s",
18021924
parent_snapshot,
18031925
(bch2_bkey_val_to_text(&buf, c, d.s_c), buf.buf))) {
1804-
u32 new_parent_subvol;
1805-
ret = find_snapshot_subvol(trans, d.k->p.snapshot, &new_parent_subvol);
1806-
if (ret)
1807-
goto err;
1926+
if (!new_parent_subvol) {
1927+
bch_err(c, "could not find a subvol for snapshot %u", d.k->p.snapshot);
1928+
return -BCH_ERR_fsck_repair_unimplemented;
1929+
}
18081930

18091931
struct bkey_i_dirent *new_dirent = bch2_bkey_make_mut_typed(trans, iter, &d.s_c, 0, dirent);
18101932
ret = PTR_ERR_OR_ZERO(new_dirent);
@@ -1850,23 +1972,30 @@ static int check_dirent_to_subvol(struct btree_trans *trans, struct btree_iter *
18501972

18511973
ret = lookup_inode(trans, target_inum, &subvol_root, &target_snapshot);
18521974
if (ret && !bch2_err_matches(ret, ENOENT))
1853-
return ret;
1975+
goto err;
18541976

1855-
if (fsck_err_on(parent_subvol != subvol_root.bi_parent_subvol,
1977+
if (ret) {
1978+
bch_err(c, "subvol %u points to missing inode root %llu", target_subvol, target_inum);
1979+
ret = -BCH_ERR_fsck_repair_unimplemented;
1980+
ret = 0;
1981+
goto err;
1982+
}
1983+
1984+
if (fsck_err_on(!ret && parent_subvol != subvol_root.bi_parent_subvol,
18561985
c, inode_bi_parent_wrong,
18571986
"subvol root %llu has wrong bi_parent_subvol: got %u, should be %u",
18581987
target_inum,
18591988
subvol_root.bi_parent_subvol, parent_subvol)) {
18601989
subvol_root.bi_parent_subvol = parent_subvol;
18611990
ret = __bch2_fsck_write_inode(trans, &subvol_root, target_snapshot);
18621991
if (ret)
1863-
return ret;
1992+
goto err;
18641993
}
18651994

18661995
ret = check_dirent_target(trans, iter, d, &subvol_root,
18671996
target_snapshot);
18681997
if (ret)
1869-
return ret;
1998+
goto err;
18701999
out:
18712000
err:
18722001
fsck_err:

0 commit comments

Comments
 (0)