mirror of
https://github.com/kdave/btrfs-progs
synced 2025-02-03 03:11:46 +00:00
btrfs-progs: check for matching free space in cache
We have this check in the kernel but not in userspace, which makes fsck fail when we wouldn't have a problem in the kernel. This was meant to catch this case because it really isn't good, unfortunately it will require a design change to fix in the kernel so in the meantime add this check so we can be sure our tests only catch real problems. Thanks, Signed-off-by: Josef Bacik <jbacik@fb.com> Signed-off-by: David Sterba <dsterba@suse.cz>
This commit is contained in:
parent
fb399a1301
commit
2681e00f00
1
ctree.h
1
ctree.h
@ -936,6 +936,7 @@ struct btrfs_block_group_cache {
|
|||||||
struct btrfs_block_group_item item;
|
struct btrfs_block_group_item item;
|
||||||
struct btrfs_space_info *space_info;
|
struct btrfs_space_info *space_info;
|
||||||
struct btrfs_free_space_ctl *free_space_ctl;
|
struct btrfs_free_space_ctl *free_space_ctl;
|
||||||
|
u64 bytes_super;
|
||||||
u64 pinned;
|
u64 pinned;
|
||||||
u64 flags;
|
u64 flags;
|
||||||
int cached;
|
int cached;
|
||||||
|
@ -3140,6 +3140,54 @@ error:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void account_super_bytes(struct btrfs_fs_info *fs_info,
|
||||||
|
struct btrfs_block_group_cache *cache)
|
||||||
|
{
|
||||||
|
u64 bytenr;
|
||||||
|
u64 *logical;
|
||||||
|
int stripe_len;
|
||||||
|
int i, nr, ret;
|
||||||
|
|
||||||
|
if (cache->key.objectid < BTRFS_SUPER_INFO_OFFSET) {
|
||||||
|
stripe_len = BTRFS_SUPER_INFO_OFFSET - cache->key.objectid;
|
||||||
|
cache->bytes_super += stripe_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
|
||||||
|
bytenr = btrfs_sb_offset(i);
|
||||||
|
ret = btrfs_rmap_block(&fs_info->mapping_tree,
|
||||||
|
cache->key.objectid, bytenr,
|
||||||
|
0, &logical, &nr, &stripe_len);
|
||||||
|
if (ret)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (nr--) {
|
||||||
|
u64 start, len;
|
||||||
|
|
||||||
|
if (logical[nr] > cache->key.objectid +
|
||||||
|
cache->key.offset)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (logical[nr] + stripe_len <= cache->key.objectid)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
start = logical[nr];
|
||||||
|
if (start < cache->key.objectid) {
|
||||||
|
start = cache->key.objectid;
|
||||||
|
len = (logical[nr] + stripe_len) - start;
|
||||||
|
} else {
|
||||||
|
len = min_t(u64, stripe_len,
|
||||||
|
cache->key.objectid +
|
||||||
|
cache->key.offset - start);
|
||||||
|
}
|
||||||
|
|
||||||
|
cache->bytes_super += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(logical);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int btrfs_read_block_groups(struct btrfs_root *root)
|
int btrfs_read_block_groups(struct btrfs_root *root)
|
||||||
{
|
{
|
||||||
struct btrfs_path *path;
|
struct btrfs_path *path;
|
||||||
@ -3201,6 +3249,8 @@ int btrfs_read_block_groups(struct btrfs_root *root)
|
|||||||
if (btrfs_chunk_readonly(root, cache->key.objectid))
|
if (btrfs_chunk_readonly(root, cache->key.objectid))
|
||||||
cache->ro = 1;
|
cache->ro = 1;
|
||||||
|
|
||||||
|
account_super_bytes(info, cache);
|
||||||
|
|
||||||
ret = update_space_info(info, cache->flags, found_key.offset,
|
ret = update_space_info(info, cache->flags, found_key.offset,
|
||||||
btrfs_block_group_used(&cache->item),
|
btrfs_block_group_used(&cache->item),
|
||||||
&space_info);
|
&space_info);
|
||||||
@ -3242,6 +3292,7 @@ btrfs_add_block_group(struct btrfs_fs_info *fs_info, u64 bytes_used, u64 type,
|
|||||||
cache->flags = type;
|
cache->flags = type;
|
||||||
btrfs_set_block_group_flags(&cache->item, type);
|
btrfs_set_block_group_flags(&cache->item, type);
|
||||||
|
|
||||||
|
account_super_bytes(fs_info, cache);
|
||||||
ret = update_space_info(fs_info, cache->flags, size, bytes_used,
|
ret = update_space_info(fs_info, cache->flags, size, bytes_used,
|
||||||
&cache->space_info);
|
&cache->space_info);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
@ -428,7 +428,9 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
|
|||||||
{
|
{
|
||||||
struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
|
struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
|
||||||
struct btrfs_path *path;
|
struct btrfs_path *path;
|
||||||
|
u64 used = btrfs_block_group_used(&block_group->item);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
int matched;
|
||||||
|
|
||||||
path = btrfs_alloc_path();
|
path = btrfs_alloc_path();
|
||||||
if (!path)
|
if (!path)
|
||||||
@ -438,6 +440,15 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
|
|||||||
block_group->key.objectid);
|
block_group->key.objectid);
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
|
|
||||||
|
matched = (ctl->free_space == (block_group->key.offset - used -
|
||||||
|
block_group->bytes_super));
|
||||||
|
if (ret == 1 && !matched) {
|
||||||
|
__btrfs_remove_free_space_cache(ctl);
|
||||||
|
printf("block group %llu has wrong amount of free space",
|
||||||
|
block_group->key.objectid);
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user