Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 165908
b: refs/heads/master
c: ba1bf48
h: refs/heads/master
v: v3
  • Loading branch information
Josef Bacik authored and Chris Mason committed Sep 21, 2009
1 parent b300f04 commit 4ff629b
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 19 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 1fb58a6051cd904a9f8e0344b22e31921d6b5a4d
refs/heads/master: ba1bf4818baf68d914ef9e3b06fbea6acb674fe4
1 change: 1 addition & 0 deletions trunk/fs/btrfs/ctree.h
Original file line number Diff line number Diff line change
Expand Up @@ -2006,6 +2006,7 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
int btrfs_extent_readonly(struct btrfs_root *root, u64 bytenr);
int btrfs_free_block_groups(struct btrfs_fs_info *info);
int btrfs_read_block_groups(struct btrfs_root *root);
int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr);
int btrfs_make_block_group(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytes_used,
u64 type, u64 chunk_objectid, u64 chunk_offset,
Expand Down
87 changes: 87 additions & 0 deletions trunk/fs/btrfs/extent-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -7402,6 +7402,93 @@ int btrfs_relocate_block_group(struct btrfs_root *root, u64 group_start)
}
#endif

/*
* checks to see if its even possible to relocate this block group.
*
* @return - -1 if it's not a good idea to relocate this block group, 0 if its
* ok to go ahead and try.
*/
int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
{
struct btrfs_block_group_cache *block_group;
struct btrfs_space_info *space_info;
struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
struct btrfs_device *device;
int full = 0;
int ret = 0;

block_group = btrfs_lookup_block_group(root->fs_info, bytenr);

/* odd, couldn't find the block group, leave it alone */
if (!block_group)
return -1;

/* no bytes used, we're good */
if (!btrfs_block_group_used(&block_group->item))
goto out;

space_info = block_group->space_info;
spin_lock(&space_info->lock);

full = space_info->full;

/*
* if this is the last block group we have in this space, we can't
* relocate it.
*/
if (space_info->total_bytes == block_group->key.offset) {
ret = -1;
spin_unlock(&space_info->lock);
goto out;
}

/*
* need to make sure we have room in the space to handle all of the
* extents from this block group. If we can, we're good
*/
if (space_info->bytes_used + space_info->bytes_reserved +
space_info->bytes_pinned + space_info->bytes_readonly +
btrfs_block_group_used(&block_group->item) <
space_info->total_bytes) {
spin_unlock(&space_info->lock);
goto out;
}
spin_unlock(&space_info->lock);

/*
* ok we don't have enough space, but maybe we have free space on our
* devices to allocate new chunks for relocation, so loop through our
* alloc devices and guess if we have enough space. However, if we
* were marked as full, then we know there aren't enough chunks, and we
* can just return.
*/
ret = -1;
if (full)
goto out;

mutex_lock(&root->fs_info->chunk_mutex);
list_for_each_entry(device, &fs_devices->alloc_list, dev_alloc_list) {
u64 min_free = btrfs_block_group_used(&block_group->item);
u64 dev_offset, max_avail;

/*
* check to make sure we can actually find a chunk with enough
* space to fit our block group in.
*/
if (device->total_bytes > device->bytes_used + min_free) {
ret = find_free_dev_extent(NULL, device, min_free,
&dev_offset, &max_avail);
if (!ret)
break;
ret = -1;
}
}
mutex_unlock(&root->fs_info->chunk_mutex);
out:
btrfs_put_block_group(block_group);
return ret;
}

static int find_first_block_group(struct btrfs_root *root,
struct btrfs_path *path, struct btrfs_key *key)
{
Expand Down
75 changes: 57 additions & 18 deletions trunk/fs/btrfs/volumes.c
Original file line number Diff line number Diff line change
Expand Up @@ -719,10 +719,9 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
* called very infrequently and that a given device has a small number
* of extents
*/
static noinline int find_free_dev_extent(struct btrfs_trans_handle *trans,
struct btrfs_device *device,
u64 num_bytes, u64 *start,
u64 *max_avail)
int find_free_dev_extent(struct btrfs_trans_handle *trans,
struct btrfs_device *device, u64 num_bytes,
u64 *start, u64 *max_avail)
{
struct btrfs_key key;
struct btrfs_root *root = device->dev_root;
Expand Down Expand Up @@ -1736,6 +1735,10 @@ static int btrfs_relocate_chunk(struct btrfs_root *root,
extent_root = root->fs_info->extent_root;
em_tree = &root->fs_info->mapping_tree.map_tree;

ret = btrfs_can_relocate(extent_root, chunk_offset);
if (ret)
return -ENOSPC;

/* step one, relocate all the extents inside this chunk */
ret = btrfs_relocate_block_group(extent_root, chunk_offset);
BUG_ON(ret);
Expand Down Expand Up @@ -1807,12 +1810,15 @@ static int btrfs_relocate_sys_chunks(struct btrfs_root *root)
struct btrfs_key found_key;
u64 chunk_tree = chunk_root->root_key.objectid;
u64 chunk_type;
bool retried = false;
int failed = 0;
int ret;

path = btrfs_alloc_path();
if (!path)
return -ENOMEM;

again:
key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
key.offset = (u64)-1;
key.type = BTRFS_CHUNK_ITEM_KEY;
Expand Down Expand Up @@ -1842,14 +1848,25 @@ static int btrfs_relocate_sys_chunks(struct btrfs_root *root)
ret = btrfs_relocate_chunk(chunk_root, chunk_tree,
found_key.objectid,
found_key.offset);
BUG_ON(ret);
if (ret == -ENOSPC)
failed++;
else if (ret)
BUG();
}

if (found_key.offset == 0)
break;
key.offset = found_key.offset - 1;
}
ret = 0;
if (failed && !retried) {
failed = 0;
retried = true;
goto again;
} else if (failed && retried) {
WARN_ON(1);
ret = -ENOSPC;
}
error:
btrfs_free_path(path);
return ret;
Expand Down Expand Up @@ -1894,6 +1911,8 @@ int btrfs_balance(struct btrfs_root *dev_root)
continue;

ret = btrfs_shrink_device(device, old_size - size_to_free);
if (ret == -ENOSPC)
break;
BUG_ON(ret);

trans = btrfs_start_transaction(dev_root, 1);
Expand Down Expand Up @@ -1938,17 +1957,17 @@ int btrfs_balance(struct btrfs_root *dev_root)
chunk = btrfs_item_ptr(path->nodes[0],
path->slots[0],
struct btrfs_chunk);
key.offset = found_key.offset;
/* chunk zero is special */
if (key.offset == 0)
if (found_key.offset == 0)
break;

btrfs_release_path(chunk_root, path);
ret = btrfs_relocate_chunk(chunk_root,
chunk_root->root_key.objectid,
found_key.objectid,
found_key.offset);
BUG_ON(ret);
BUG_ON(ret && ret != -ENOSPC);
key.offset = found_key.offset - 1;
}
ret = 0;
error:
Expand All @@ -1974,10 +1993,13 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
u64 chunk_offset;
int ret;
int slot;
int failed = 0;
bool retried = false;
struct extent_buffer *l;
struct btrfs_key key;
struct btrfs_super_block *super_copy = &root->fs_info->super_copy;
u64 old_total = btrfs_super_total_bytes(super_copy);
u64 old_size = device->total_bytes;
u64 diff = device->total_bytes - new_size;

if (new_size >= device->total_bytes)
Expand All @@ -1987,12 +2009,6 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
if (!path)
return -ENOMEM;

trans = btrfs_start_transaction(root, 1);
if (!trans) {
ret = -ENOMEM;
goto done;
}

path->reada = 2;

lock_chunks(root);
Expand All @@ -2001,8 +2017,8 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
if (device->writeable)
device->fs_devices->total_rw_bytes -= diff;
unlock_chunks(root);
btrfs_end_transaction(trans, root);

again:
key.objectid = device->devid;
key.offset = (u64)-1;
key.type = BTRFS_DEV_EXTENT_KEY;
Expand All @@ -2017,21 +2033,26 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
goto done;
if (ret) {
ret = 0;
btrfs_release_path(root, path);
break;
}

l = path->nodes[0];
slot = path->slots[0];
btrfs_item_key_to_cpu(l, &key, path->slots[0]);

if (key.objectid != device->devid)
if (key.objectid != device->devid) {
btrfs_release_path(root, path);
break;
}

dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent);
length = btrfs_dev_extent_length(l, dev_extent);

if (key.offset + length <= new_size)
if (key.offset + length <= new_size) {
btrfs_release_path(root, path);
break;
}

chunk_tree = btrfs_dev_extent_chunk_tree(l, dev_extent);
chunk_objectid = btrfs_dev_extent_chunk_objectid(l, dev_extent);
Expand All @@ -2040,8 +2061,26 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)

ret = btrfs_relocate_chunk(root, chunk_tree, chunk_objectid,
chunk_offset);
if (ret)
if (ret && ret != -ENOSPC)
goto done;
if (ret == -ENOSPC)
failed++;
key.offset -= 1;
}

if (failed && !retried) {
failed = 0;
retried = true;
goto again;
} else if (failed && retried) {
ret = -ENOSPC;
lock_chunks(root);

device->total_bytes = old_size;
if (device->writeable)
device->fs_devices->total_rw_bytes += diff;
unlock_chunks(root);
goto done;
}

/* Shrinking succeeded, else we would be at "done". */
Expand Down
3 changes: 3 additions & 0 deletions trunk/fs/btrfs/volumes.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,4 +181,7 @@ int btrfs_balance(struct btrfs_root *dev_root);
void btrfs_unlock_volumes(void);
void btrfs_lock_volumes(void);
int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset);
int find_free_dev_extent(struct btrfs_trans_handle *trans,
struct btrfs_device *device, u64 num_bytes,
u64 *start, u64 *max_avail);
#endif

0 comments on commit 4ff629b

Please sign in to comment.