Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions check/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3550,6 +3550,11 @@ static int check_root_refs(struct btrfs_root *root,
*/
if (!rec->found_root_item)
continue;
if (opt_check_repair) {
ret = repair_subvol_orphan_item(gfs_info, rec->objectid);
if (!ret)
continue;
}
errors++;
fprintf(stderr, "fs tree %llu missing orphan item\n", rec->objectid);
}
Expand Down
33 changes: 33 additions & 0 deletions check/mode-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -1672,3 +1672,36 @@ int check_and_repair_super_num_devs(struct btrfs_fs_info *fs_info)
printf("Successfully reset super num devices to %u\n", found_devs);
return 0;
}

int repair_subvol_orphan_item(struct btrfs_fs_info *fs_info, u64 rootid)
{
struct btrfs_root *tree_root = fs_info->tree_root;
struct btrfs_trans_handle *trans;
struct btrfs_path path = { 0 };
int ret;

trans = btrfs_start_transaction(tree_root, 1);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
errno = -ret;
error_msg(ERROR_MSG_START_TRANS, "%m");
return ret;
}
ret = btrfs_add_orphan_item(trans, tree_root, &path, rootid);
btrfs_release_path(&path);
if (ret < 0) {
errno = -ret;
error("failed to insert orphan item for subvolume %llu: %m", rootid);
btrfs_abort_transaction(trans, ret);
btrfs_commit_transaction(trans, tree_root);
return ret;
}
ret = btrfs_commit_transaction(trans, tree_root);
if (ret < 0) {
errno = -ret;
error_msg(ERROR_MSG_COMMIT_TRANS, "%m");
return ret;
}
printf("Added back missing orphan item for subvolume %llu\n", rootid);
return 0;
}
1 change: 1 addition & 0 deletions check/mode-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,5 +197,6 @@ int repair_dev_item_bytes_used(struct btrfs_fs_info *fs_info,
int fill_csum_tree(struct btrfs_trans_handle *trans, bool search_fs_tree);

int check_and_repair_super_num_devs(struct btrfs_fs_info *fs_info);
int repair_subvol_orphan_item(struct btrfs_fs_info *fs_info, u64 rootid);

#endif
13 changes: 10 additions & 3 deletions check/mode-lowmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -5569,9 +5569,16 @@ static int check_btrfs_root(struct btrfs_root *root, int check_all)
* If this tree is a subvolume (not a reloc tree) and has no refs, there
* should be an orphan item for it, or this subvolume will never be deleted.
*/
if (btrfs_root_refs(root_item) == 0 && is_fstree(btrfs_root_id(root))) {
if (!has_orphan_item(root->fs_info->tree_root,
btrfs_root_id(root))) {
if (btrfs_root_refs(root_item) == 0 && is_fstree(btrfs_root_id(root)) &&
!has_orphan_item(root->fs_info->tree_root, btrfs_root_id(root))) {
bool repaired = false;

if (opt_check_repair) {
ret = repair_subvol_orphan_item(root->fs_info, btrfs_root_id(root));
if (!ret)
repaired = true;
}
if (!repaired) {
error("missing orphan item for root %lld", btrfs_root_id(root));
err |= REFERENCER_MISSING;
}
Expand Down
146 changes: 71 additions & 75 deletions kernel-shared/extent-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -1980,90 +1980,86 @@ static int __free_extent(struct btrfs_trans_handle *trans,
bytenr, num_bytes, parent,
root_objectid, owner_objectid,
owner_offset);
if (ret == 0) {
extent_slot = path->slots[0];
while (extent_slot >= 0) {
btrfs_item_key_to_cpu(path->nodes[0], &key,
extent_slot);
if (key.objectid != bytenr)
break;
if (key.type == BTRFS_EXTENT_ITEM_KEY &&
key.offset == num_bytes) {
found_extent = 1;
break;
}
if (key.type == BTRFS_METADATA_ITEM_KEY &&
key.offset == owner_objectid) {
found_extent = 1;
break;
}
if (path->slots[0] - extent_slot > 5)
break;
extent_slot--;
if (ret) {
error("unable to find ref byte nr %llu parent %llu root %llu owner %llu offset %llu ret %d\n",
bytenr, parent, root_objectid, owner_objectid,
owner_offset, ret);
if (path->nodes[0]) {
printf("path->slots[0]: %d path->nodes[0]:\n", path->slots[0]);
btrfs_print_leaf(path->nodes[0]);
}
if (!found_extent) {
BUG_ON(iref);
ret = remove_extent_backref(trans, extent_root, path,
NULL, refs_to_drop,
is_data);
BUG_ON(ret);
btrfs_release_path(path);
ret = -EIO;
goto fail;
}
extent_slot = path->slots[0];
while (extent_slot >= 0) {
btrfs_item_key_to_cpu(path->nodes[0], &key,
extent_slot);
if (key.objectid != bytenr)
break;
if (key.type == BTRFS_EXTENT_ITEM_KEY &&
key.offset == num_bytes) {
found_extent = 1;
break;
}
if (key.type == BTRFS_METADATA_ITEM_KEY &&
key.offset == owner_objectid) {
found_extent = 1;
break;
}
if (path->slots[0] - extent_slot > 5)
break;
extent_slot--;
}
if (!found_extent) {
BUG_ON(iref);
ret = remove_extent_backref(trans, extent_root, path,
NULL, refs_to_drop,
is_data);
BUG_ON(ret);
btrfs_release_path(path);

key.objectid = bytenr;
key.objectid = bytenr;

if (skinny_metadata) {
key.type = BTRFS_METADATA_ITEM_KEY;
key.offset = owner_objectid;
} else {
key.type = BTRFS_EXTENT_ITEM_KEY;
key.offset = num_bytes;
}
if (skinny_metadata) {
key.type = BTRFS_METADATA_ITEM_KEY;
key.offset = owner_objectid;
} else {
key.type = BTRFS_EXTENT_ITEM_KEY;
key.offset = num_bytes;
}

ret = btrfs_search_slot(trans, extent_root,
&key, path, -1, 1);
if (ret > 0 && skinny_metadata && path->slots[0]) {
path->slots[0]--;
btrfs_item_key_to_cpu(path->nodes[0],
&key,
path->slots[0]);
if (key.objectid == bytenr &&
key.type == BTRFS_EXTENT_ITEM_KEY &&
key.offset == num_bytes)
ret = 0;
}

if (ret > 0 && skinny_metadata) {
skinny_metadata = 0;
btrfs_release_path(path);
key.type = BTRFS_EXTENT_ITEM_KEY;
key.offset = num_bytes;
ret = btrfs_search_slot(trans, extent_root,
&key, path, -1, 1);
if (ret > 0 && skinny_metadata && path->slots[0]) {
path->slots[0]--;
btrfs_item_key_to_cpu(path->nodes[0],
&key,
path->slots[0]);
if (key.objectid == bytenr &&
key.type == BTRFS_EXTENT_ITEM_KEY &&
key.offset == num_bytes)
ret = 0;
}

if (ret > 0 && skinny_metadata) {
skinny_metadata = 0;
btrfs_release_path(path);
key.type = BTRFS_EXTENT_ITEM_KEY;
key.offset = num_bytes;
ret = btrfs_search_slot(trans, extent_root,
&key, path, -1, 1);
}
}

if (ret) {
printk(KERN_ERR "umm, got %d back from search"
", was looking for %llu\n", ret,
(unsigned long long)bytenr);
btrfs_print_leaf(path->nodes[0]);
}
BUG_ON(ret);
extent_slot = path->slots[0];
if (ret) {
printk(KERN_ERR "umm, got %d back from search"
", was looking for %llu\n", ret,
(unsigned long long)bytenr);
btrfs_print_leaf(path->nodes[0]);
}
} else {
printk(KERN_ERR "btrfs unable to find ref byte nr %llu "
"parent %llu root %llu owner %llu offset %llu\n",
(unsigned long long)bytenr,
(unsigned long long)parent,
(unsigned long long)root_objectid,
(unsigned long long)owner_objectid,
(unsigned long long)owner_offset);
printf("path->slots[0]: %d path->nodes[0]:\n", path->slots[0]);
btrfs_print_leaf(path->nodes[0]);
ret = -EIO;
goto fail;
BUG_ON(ret);
extent_slot = path->slots[0];
}

leaf = path->nodes[0];
item_size = btrfs_item_size(leaf, extent_slot);
if (item_size < sizeof(*ei)) {
Expand Down
Empty file.
14 changes: 0 additions & 14 deletions tests/fsck-tests/066-missing-root-orphan-item/test.sh

This file was deleted.