Skip to content

Commit a17fa7b

Browse files
adam900710kdave
authored andcommitted
btrfs-progs: check: add repair ability for missing orphan root item
There is a known bug in older kernels that orphan items can be missing for dropped subvolumes. This makes the subvolumes unable to be removed on the next mount, and recent kernel commit 4289b494ac55 ("btrfs: do not allow relocation of partially dropped subvolumes") introduced one extra safe net to catch such problem. But unfortunately there is no way to repair it. Add the repair ability to both the original and lowmem modes. Reviewed-by: Boris Burkov <[email protected]> Signed-off-by: Qu Wenruo <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 733eff3 commit a17fa7b

File tree

4 files changed

+49
-3
lines changed

4 files changed

+49
-3
lines changed

check/main.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3550,6 +3550,11 @@ static int check_root_refs(struct btrfs_root *root,
35503550
*/
35513551
if (!rec->found_root_item)
35523552
continue;
3553+
if (opt_check_repair) {
3554+
ret = repair_subvol_orphan_item(gfs_info, rec->objectid);
3555+
if (!ret)
3556+
continue;
3557+
}
35533558
errors++;
35543559
fprintf(stderr, "fs tree %llu missing orphan item\n", rec->objectid);
35553560
}

check/mode-common.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1672,3 +1672,36 @@ int check_and_repair_super_num_devs(struct btrfs_fs_info *fs_info)
16721672
printf("Successfully reset super num devices to %u\n", found_devs);
16731673
return 0;
16741674
}
1675+
1676+
int repair_subvol_orphan_item(struct btrfs_fs_info *fs_info, u64 rootid)
1677+
{
1678+
struct btrfs_root *tree_root = fs_info->tree_root;
1679+
struct btrfs_trans_handle *trans;
1680+
struct btrfs_path path = { 0 };
1681+
int ret;
1682+
1683+
trans = btrfs_start_transaction(tree_root, 1);
1684+
if (IS_ERR(trans)) {
1685+
ret = PTR_ERR(trans);
1686+
errno = -ret;
1687+
error_msg(ERROR_MSG_START_TRANS, "%m");
1688+
return ret;
1689+
}
1690+
ret = btrfs_add_orphan_item(trans, tree_root, &path, rootid);
1691+
btrfs_release_path(&path);
1692+
if (ret < 0) {
1693+
errno = -ret;
1694+
error("failed to insert orphan item for subvolume %llu: %m", rootid);
1695+
btrfs_abort_transaction(trans, ret);
1696+
btrfs_commit_transaction(trans, tree_root);
1697+
return ret;
1698+
}
1699+
ret = btrfs_commit_transaction(trans, tree_root);
1700+
if (ret < 0) {
1701+
errno = -ret;
1702+
error_msg(ERROR_MSG_COMMIT_TRANS, "%m");
1703+
return ret;
1704+
}
1705+
pr_verbose(LOG_DEFAULT, "Added back missing orphan item for subvolume %llu\n", rootid);
1706+
return 0;
1707+
}

check/mode-common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,5 +197,6 @@ int repair_dev_item_bytes_used(struct btrfs_fs_info *fs_info,
197197
int fill_csum_tree(struct btrfs_trans_handle *trans, bool search_fs_tree);
198198

199199
int check_and_repair_super_num_devs(struct btrfs_fs_info *fs_info);
200+
int repair_subvol_orphan_item(struct btrfs_fs_info *fs_info, u64 rootid);
200201

201202
#endif

check/mode-lowmem.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5569,9 +5569,16 @@ static int check_btrfs_root(struct btrfs_root *root, int check_all)
55695569
* If this tree is a subvolume (not a reloc tree) and has no refs, there
55705570
* should be an orphan item for it, or this subvolume will never be deleted.
55715571
*/
5572-
if (btrfs_root_refs(root_item) == 0 && is_fstree(btrfs_root_id(root))) {
5573-
if (!has_orphan_item(root->fs_info->tree_root,
5574-
btrfs_root_id(root))) {
5572+
if (btrfs_root_refs(root_item) == 0 && is_fstree(btrfs_root_id(root)) &&
5573+
!has_orphan_item(root->fs_info->tree_root, btrfs_root_id(root))) {
5574+
bool repaired = false;
5575+
5576+
if (opt_check_repair) {
5577+
ret = repair_subvol_orphan_item(root->fs_info, btrfs_root_id(root));
5578+
if (!ret)
5579+
repaired = true;
5580+
}
5581+
if (!repaired) {
55755582
error("missing orphan item for root %lld", btrfs_root_id(root));
55765583
err |= REFERENCER_MISSING;
55775584
}

0 commit comments

Comments
 (0)