Skip to content

Commit 29cc6fb

Browse files
author
Kent Overstreet
committed
bcachefs: Fix subvol to missing root repair
We had a bug where the root inode of a subvolume was erronously deleted: bch2_evict_inode() called bch2_inode_rm(), meaning the VFS inode's i_nlink was somehow set to 0 when it shouldn't have - the inode in the btree indicated it clearly was not unlinked. This has been addressed with additional safety checks in bch2_inode_rm() - pulling in the safety checks we already were doing when deleting unlinked inodes in recovery - but the really disastrous bug was in check_subvols(), which on finding a dangling subvol (subvol with a missing root inode) would delete the subvolume. I assume this bug dates from early check_directory_structure() code, which originally handled subvolumes and normal paths - the idea being that still live contents of the subvolume would get reattached somewhere. But that's incorrect, and disastrously so; deleting a subvolume triggers deleting the snapshot ID it points to, deleting the entire contents. The correct way to repair is to recreate the root inode if it's missing; then any contents will get reattached under that subvolume's lost+found. Signed-off-by: Kent Overstreet <[email protected]>
1 parent 09fb85a commit 29cc6fb

File tree

1 file changed

+14
-4
lines changed

1 file changed

+14
-4
lines changed

fs/bcachefs/subvolume.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,20 @@ static int check_subvol(struct btree_trans *trans,
130130
"subvolume %llu points to missing subvolume root %llu:%u",
131131
k.k->p.offset, le64_to_cpu(subvol.v->inode),
132132
le32_to_cpu(subvol.v->snapshot))) {
133-
ret = bch2_subvolume_delete(trans, iter->pos.offset);
134-
bch_err_msg(c, ret, "deleting subvolume %llu", iter->pos.offset);
135-
ret = ret ?: -BCH_ERR_transaction_restart_nested;
136-
goto err;
133+
/*
134+
* Recreate - any contents that are still disconnected
135+
* will then get reattached under lost+found
136+
*/
137+
bch2_inode_init_early(c, &inode);
138+
bch2_inode_init_late(c, &inode, bch2_current_time(c),
139+
0, 0, S_IFDIR|0700, 0, NULL);
140+
inode.bi_inum = le64_to_cpu(subvol.v->inode);
141+
inode.bi_snapshot = le32_to_cpu(subvol.v->snapshot);
142+
inode.bi_subvol = k.k->p.offset;
143+
inode.bi_parent_subvol = le32_to_cpu(subvol.v->fs_path_parent);
144+
ret = __bch2_fsck_write_inode(trans, &inode);
145+
if (ret)
146+
goto err;
137147
}
138148
} else {
139149
goto err;

0 commit comments

Comments
 (0)