Skip to content

Commit

Permalink
Btrfs: online shrinking fixes
Browse files Browse the repository at this point in the history
While shrinking the FS, the allocation functions need to make sure
they don't try to allocate bytes past the end of the FS.

nodatacow needed an extra check to force cows when the existing extents are
past the end of the FS.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
  • Loading branch information
Chris Mason committed Sep 25, 2008
1 parent b0331a4 commit c31f883
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 11 deletions.
32 changes: 23 additions & 9 deletions fs/btrfs/extent-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,13 @@ static u64 noinline find_search_start(struct btrfs_root *root,
u64 start = 0;
u64 end = 0;
u64 cache_miss = 0;
u64 total_fs_bytes;
int wrapped = 0;

if (!cache) {
goto out;
}
total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy);
again:
ret = cache_block_group(root, cache);
if (ret)
Expand All @@ -223,6 +225,8 @@ static u64 noinline find_search_start(struct btrfs_root *root,
if (data != BTRFS_BLOCK_GROUP_MIXED &&
start + num > cache->key.objectid + cache->key.offset)
goto new_group;
if (start + num > total_fs_bytes)
goto new_group;
return start;
}
out:
Expand All @@ -239,7 +243,7 @@ static u64 noinline find_search_start(struct btrfs_root *root,
last = cache->key.objectid + cache->key.offset;
wrapped:
cache = btrfs_lookup_block_group(root->fs_info, last);
if (!cache) {
if (!cache || cache->key.objectid >= total_fs_bytes) {
no_cache:
if (!wrapped) {
wrapped = 1;
Expand Down Expand Up @@ -287,13 +291,15 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
u64 end;
u64 free_check;
u64 ptr;
u64 total_fs_bytes;
int bit;
int ret;
int full_search = 0;
int factor = 8;
int data_swap = 0;

block_group_cache = &info->block_group_cache;
total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy);

if (!owner)
factor = 8;
Expand All @@ -306,7 +312,7 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
else
bit = BLOCK_GROUP_METADATA;

if (search_start) {
if (search_start && search_start < total_fs_bytes) {
struct btrfs_block_group_cache *shint;
shint = btrfs_lookup_block_group(info, search_start);
if (shint && (shint->data == data ||
Expand All @@ -318,8 +324,8 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
}
}
}
if (hint && (hint->data == data ||
hint->data == BTRFS_BLOCK_GROUP_MIXED)) {
if (hint && hint->key.objectid < total_fs_bytes &&
(hint->data == data || hint->data == BTRFS_BLOCK_GROUP_MIXED)) {
used = btrfs_block_group_used(&hint->item);
if (used + hint->pinned <
div_factor(hint->key.offset, factor)) {
Expand All @@ -333,6 +339,8 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
else
hint_last = search_start;

if (hint_last >= total_fs_bytes)
hint_last = search_start;
last = hint_last;
}
again:
Expand All @@ -350,6 +358,9 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
last = cache->key.objectid + cache->key.offset;
used = btrfs_block_group_used(&cache->item);

if (cache->key.objectid > total_fs_bytes)
break;

if (full_search)
free_check = cache->key.offset;
else
Expand Down Expand Up @@ -1420,8 +1431,8 @@ static int noinline find_free_extent(struct btrfs_trans_handle *trans,
data = BTRFS_BLOCK_GROUP_MIXED;
}

if (search_end == (u64)-1)
search_end = btrfs_super_total_bytes(&info->super_copy);
search_end = min(search_end,
btrfs_super_total_bytes(&info->super_copy));
if (hint_byte) {
block_group = btrfs_lookup_block_group(info, hint_byte);
if (!block_group)
Expand Down Expand Up @@ -1617,7 +1628,8 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
{
int ret;
int pending_ret;
u64 super_used, root_used;
u64 super_used;
u64 root_used;
u64 search_start = 0;
u64 new_hint;
struct btrfs_fs_info *info = root->fs_info;
Expand All @@ -1636,6 +1648,8 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
search_start, search_end, hint_byte, ins,
trans->alloc_exclude_start,
trans->alloc_exclude_nr, data);
if (ret)
printk("find free extent returns %d\n", ret);
BUG_ON(ret);
if (ret)
return ret;
Expand Down Expand Up @@ -2292,8 +2306,6 @@ static int noinline relocate_one_extent(struct btrfs_root *extent_root,
while(1) {
ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);

BUG_ON(ret == 0);

if (ret < 0)
goto out;

Expand Down Expand Up @@ -2340,6 +2352,8 @@ int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 new_size)
int progress = 0;

btrfs_set_super_total_bytes(&info->super_copy, new_size);
clear_extent_dirty(&info->free_space_cache, new_size, (u64)-1,
GFP_NOFS);
block_group_cache = &info->block_group_cache;
path = btrfs_alloc_path();
root = root->fs_info->extent_root;
Expand Down
15 changes: 13 additions & 2 deletions fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ static int run_delalloc_nocow(struct inode *inode, u64 start, u64 end)
u64 bytenr;
u64 cow_end;
u64 loops = 0;
u64 total_fs_bytes;
struct btrfs_root *root = BTRFS_I(inode)->root;
struct extent_buffer *leaf;
int found_type;
Expand All @@ -157,6 +158,7 @@ static int run_delalloc_nocow(struct inode *inode, u64 start, u64 end)
int err;
struct btrfs_key found_key;

total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy);
path = btrfs_alloc_path();
BUG_ON(!path);
again:
Expand Down Expand Up @@ -189,8 +191,10 @@ static int run_delalloc_nocow(struct inode *inode, u64 start, u64 end)
found_type = btrfs_file_extent_type(leaf, item);
extent_start = found_key.offset;
if (found_type == BTRFS_FILE_EXTENT_REG) {
extent_end = extent_start +
btrfs_file_extent_num_bytes(leaf, item);
u64 extent_num_bytes;

extent_num_bytes = btrfs_file_extent_num_bytes(leaf, item);
extent_end = extent_start + extent_num_bytes;
err = 0;

if (loops && start != extent_start)
Expand All @@ -204,6 +208,13 @@ static int run_delalloc_nocow(struct inode *inode, u64 start, u64 end)
if (bytenr == 0)
goto not_found;

/*
* we may be called by the resizer, make sure we're inside
* the limits of the FS
*/
if (bytenr + extent_num_bytes > total_fs_bytes)
goto not_found;

if (btrfs_count_snapshots_in_path(root, path, bytenr) != 1) {
goto not_found;
}
Expand Down

0 comments on commit c31f883

Please sign in to comment.