Btrfs: remove dead code
This patch removes a bunch of dead code from the snapshot removal stuff. It was confusing me when doing the metadata ENOSPC stuff so I killed it. Signed-off-by: Josef Bacik <jbacik@redhat.com> Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
parent
f019f4264a
commit
f61408b81c
@ -4462,430 +4462,6 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
||||
return buf;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, struct extent_buffer *leaf)
|
||||
{
|
||||
u64 disk_bytenr;
|
||||
u64 num_bytes;
|
||||
struct btrfs_key key;
|
||||
struct btrfs_file_extent_item *fi;
|
||||
u32 nritems;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
BUG_ON(!btrfs_is_leaf(leaf));
|
||||
nritems = btrfs_header_nritems(leaf);
|
||||
|
||||
for (i = 0; i < nritems; i++) {
|
||||
cond_resched();
|
||||
btrfs_item_key_to_cpu(leaf, &key, i);
|
||||
|
||||
/* only extents have references, skip everything else */
|
||||
if (btrfs_key_type(&key) != BTRFS_EXTENT_DATA_KEY)
|
||||
continue;
|
||||
|
||||
fi = btrfs_item_ptr(leaf, i, struct btrfs_file_extent_item);
|
||||
|
||||
/* inline extents live in the btree, they don't have refs */
|
||||
if (btrfs_file_extent_type(leaf, fi) ==
|
||||
BTRFS_FILE_EXTENT_INLINE)
|
||||
continue;
|
||||
|
||||
disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
|
||||
|
||||
/* holes don't have refs */
|
||||
if (disk_bytenr == 0)
|
||||
continue;
|
||||
|
||||
num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi);
|
||||
ret = btrfs_free_extent(trans, root, disk_bytenr, num_bytes,
|
||||
leaf->start, 0, key.objectid, 0);
|
||||
BUG_ON(ret);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static noinline int cache_drop_leaf_ref(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_leaf_ref *ref)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
struct btrfs_extent_info *info;
|
||||
struct refsort *sorted;
|
||||
|
||||
if (ref->nritems == 0)
|
||||
return 0;
|
||||
|
||||
sorted = kmalloc(sizeof(*sorted) * ref->nritems, GFP_NOFS);
|
||||
for (i = 0; i < ref->nritems; i++) {
|
||||
sorted[i].bytenr = ref->extents[i].bytenr;
|
||||
sorted[i].slot = i;
|
||||
}
|
||||
sort(sorted, ref->nritems, sizeof(struct refsort), refsort_cmp, NULL);
|
||||
|
||||
/*
|
||||
* the items in the ref were sorted when the ref was inserted
|
||||
* into the ref cache, so this is already in order
|
||||
*/
|
||||
for (i = 0; i < ref->nritems; i++) {
|
||||
info = ref->extents + sorted[i].slot;
|
||||
ret = btrfs_free_extent(trans, root, info->bytenr,
|
||||
info->num_bytes, ref->bytenr,
|
||||
ref->owner, ref->generation,
|
||||
info->objectid, 0);
|
||||
|
||||
atomic_inc(&root->fs_info->throttle_gen);
|
||||
wake_up(&root->fs_info->transaction_throttle);
|
||||
cond_resched();
|
||||
|
||||
BUG_ON(ret);
|
||||
info++;
|
||||
}
|
||||
|
||||
kfree(sorted);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int drop_snap_lookup_refcount(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, u64 start,
|
||||
u64 len, u32 *refs)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = btrfs_lookup_extent_refs(trans, root, start, len, refs);
|
||||
BUG_ON(ret);
|
||||
|
||||
#if 0 /* some debugging code in case we see problems here */
|
||||
/* if the refs count is one, it won't get increased again. But
|
||||
* if the ref count is > 1, someone may be decreasing it at
|
||||
* the same time we are.
|
||||
*/
|
||||
if (*refs != 1) {
|
||||
struct extent_buffer *eb = NULL;
|
||||
eb = btrfs_find_create_tree_block(root, start, len);
|
||||
if (eb)
|
||||
btrfs_tree_lock(eb);
|
||||
|
||||
mutex_lock(&root->fs_info->alloc_mutex);
|
||||
ret = lookup_extent_ref(NULL, root, start, len, refs);
|
||||
BUG_ON(ret);
|
||||
mutex_unlock(&root->fs_info->alloc_mutex);
|
||||
|
||||
if (eb) {
|
||||
btrfs_tree_unlock(eb);
|
||||
free_extent_buffer(eb);
|
||||
}
|
||||
if (*refs == 1) {
|
||||
printk(KERN_ERR "btrfs block %llu went down to one "
|
||||
"during drop_snap\n", (unsigned long long)start);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
cond_resched();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* this is used while deleting old snapshots, and it drops the refs
|
||||
* on a whole subtree starting from a level 1 node.
|
||||
*
|
||||
* The idea is to sort all the leaf pointers, and then drop the
|
||||
* ref on all the leaves in order. Most of the time the leaves
|
||||
* will have ref cache entries, so no leaf IOs will be required to
|
||||
* find the extents they have references on.
|
||||
*
|
||||
* For each leaf, any references it has are also dropped in order
|
||||
*
|
||||
* This ends up dropping the references in something close to optimal
|
||||
* order for reading and modifying the extent allocation tree.
|
||||
*/
|
||||
static noinline int drop_level_one_refs(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_path *path)
|
||||
{
|
||||
u64 bytenr;
|
||||
u64 root_owner;
|
||||
u64 root_gen;
|
||||
struct extent_buffer *eb = path->nodes[1];
|
||||
struct extent_buffer *leaf;
|
||||
struct btrfs_leaf_ref *ref;
|
||||
struct refsort *sorted = NULL;
|
||||
int nritems = btrfs_header_nritems(eb);
|
||||
int ret;
|
||||
int i;
|
||||
int refi = 0;
|
||||
int slot = path->slots[1];
|
||||
u32 blocksize = btrfs_level_size(root, 0);
|
||||
u32 refs;
|
||||
|
||||
if (nritems == 0)
|
||||
goto out;
|
||||
|
||||
root_owner = btrfs_header_owner(eb);
|
||||
root_gen = btrfs_header_generation(eb);
|
||||
sorted = kmalloc(sizeof(*sorted) * nritems, GFP_NOFS);
|
||||
|
||||
/*
|
||||
* step one, sort all the leaf pointers so we don't scribble
|
||||
* randomly into the extent allocation tree
|
||||
*/
|
||||
for (i = slot; i < nritems; i++) {
|
||||
sorted[refi].bytenr = btrfs_node_blockptr(eb, i);
|
||||
sorted[refi].slot = i;
|
||||
refi++;
|
||||
}
|
||||
|
||||
/*
|
||||
* nritems won't be zero, but if we're picking up drop_snapshot
|
||||
* after a crash, slot might be > 0, so double check things
|
||||
* just in case.
|
||||
*/
|
||||
if (refi == 0)
|
||||
goto out;
|
||||
|
||||
sort(sorted, refi, sizeof(struct refsort), refsort_cmp, NULL);
|
||||
|
||||
/*
|
||||
* the first loop frees everything the leaves point to
|
||||
*/
|
||||
for (i = 0; i < refi; i++) {
|
||||
u64 ptr_gen;
|
||||
|
||||
bytenr = sorted[i].bytenr;
|
||||
|
||||
/*
|
||||
* check the reference count on this leaf. If it is > 1
|
||||
* we just decrement it below and don't update any
|
||||
* of the refs the leaf points to.
|
||||
*/
|
||||
ret = drop_snap_lookup_refcount(trans, root, bytenr,
|
||||
blocksize, &refs);
|
||||
BUG_ON(ret);
|
||||
if (refs != 1)
|
||||
continue;
|
||||
|
||||
ptr_gen = btrfs_node_ptr_generation(eb, sorted[i].slot);
|
||||
|
||||
/*
|
||||
* the leaf only had one reference, which means the
|
||||
* only thing pointing to this leaf is the snapshot
|
||||
* we're deleting. It isn't possible for the reference
|
||||
* count to increase again later
|
||||
*
|
||||
* The reference cache is checked for the leaf,
|
||||
* and if found we'll be able to drop any refs held by
|
||||
* the leaf without needing to read it in.
|
||||
*/
|
||||
ref = btrfs_lookup_leaf_ref(root, bytenr);
|
||||
if (ref && ref->generation != ptr_gen) {
|
||||
btrfs_free_leaf_ref(root, ref);
|
||||
ref = NULL;
|
||||
}
|
||||
if (ref) {
|
||||
ret = cache_drop_leaf_ref(trans, root, ref);
|
||||
BUG_ON(ret);
|
||||
btrfs_remove_leaf_ref(root, ref);
|
||||
btrfs_free_leaf_ref(root, ref);
|
||||
} else {
|
||||
/*
|
||||
* the leaf wasn't in the reference cache, so
|
||||
* we have to read it.
|
||||
*/
|
||||
leaf = read_tree_block(root, bytenr, blocksize,
|
||||
ptr_gen);
|
||||
ret = btrfs_drop_leaf_ref(trans, root, leaf);
|
||||
BUG_ON(ret);
|
||||
free_extent_buffer(leaf);
|
||||
}
|
||||
atomic_inc(&root->fs_info->throttle_gen);
|
||||
wake_up(&root->fs_info->transaction_throttle);
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
/*
|
||||
* run through the loop again to free the refs on the leaves.
|
||||
* This is faster than doing it in the loop above because
|
||||
* the leaves are likely to be clustered together. We end up
|
||||
* working in nice chunks on the extent allocation tree.
|
||||
*/
|
||||
for (i = 0; i < refi; i++) {
|
||||
bytenr = sorted[i].bytenr;
|
||||
ret = btrfs_free_extent(trans, root, bytenr,
|
||||
blocksize, eb->start,
|
||||
root_owner, root_gen, 0, 1);
|
||||
BUG_ON(ret);
|
||||
|
||||
atomic_inc(&root->fs_info->throttle_gen);
|
||||
wake_up(&root->fs_info->transaction_throttle);
|
||||
cond_resched();
|
||||
}
|
||||
out:
|
||||
kfree(sorted);
|
||||
|
||||
/*
|
||||
* update the path to show we've processed the entire level 1
|
||||
* node. This will get saved into the root's drop_snapshot_progress
|
||||
* field so these drops are not repeated again if this transaction
|
||||
* commits.
|
||||
*/
|
||||
path->slots[1] = nritems;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* helper function for drop_snapshot, this walks down the tree dropping ref
|
||||
* counts as it goes.
|
||||
*/
|
||||
static noinline int walk_down_tree(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_path *path, int *level)
|
||||
{
|
||||
u64 root_owner;
|
||||
u64 root_gen;
|
||||
u64 bytenr;
|
||||
u64 ptr_gen;
|
||||
struct extent_buffer *next;
|
||||
struct extent_buffer *cur;
|
||||
struct extent_buffer *parent;
|
||||
u32 blocksize;
|
||||
int ret;
|
||||
u32 refs;
|
||||
|
||||
WARN_ON(*level < 0);
|
||||
WARN_ON(*level >= BTRFS_MAX_LEVEL);
|
||||
ret = drop_snap_lookup_refcount(trans, root, path->nodes[*level]->start,
|
||||
path->nodes[*level]->len, &refs);
|
||||
BUG_ON(ret);
|
||||
if (refs > 1)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* walk down to the last node level and free all the leaves
|
||||
*/
|
||||
while (*level >= 0) {
|
||||
WARN_ON(*level < 0);
|
||||
WARN_ON(*level >= BTRFS_MAX_LEVEL);
|
||||
cur = path->nodes[*level];
|
||||
|
||||
if (btrfs_header_level(cur) != *level)
|
||||
WARN_ON(1);
|
||||
|
||||
if (path->slots[*level] >=
|
||||
btrfs_header_nritems(cur))
|
||||
break;
|
||||
|
||||
/* the new code goes down to level 1 and does all the
|
||||
* leaves pointed to that node in bulk. So, this check
|
||||
* for level 0 will always be false.
|
||||
*
|
||||
* But, the disk format allows the drop_snapshot_progress
|
||||
* field in the root to leave things in a state where
|
||||
* a leaf will need cleaning up here. If someone crashes
|
||||
* with the old code and then boots with the new code,
|
||||
* we might find a leaf here.
|
||||
*/
|
||||
if (*level == 0) {
|
||||
ret = btrfs_drop_leaf_ref(trans, root, cur);
|
||||
BUG_ON(ret);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* once we get to level one, process the whole node
|
||||
* at once, including everything below it.
|
||||
*/
|
||||
if (*level == 1) {
|
||||
ret = drop_level_one_refs(trans, root, path);
|
||||
BUG_ON(ret);
|
||||
break;
|
||||
}
|
||||
|
||||
bytenr = btrfs_node_blockptr(cur, path->slots[*level]);
|
||||
ptr_gen = btrfs_node_ptr_generation(cur, path->slots[*level]);
|
||||
blocksize = btrfs_level_size(root, *level - 1);
|
||||
|
||||
ret = drop_snap_lookup_refcount(trans, root, bytenr,
|
||||
blocksize, &refs);
|
||||
BUG_ON(ret);
|
||||
|
||||
/*
|
||||
* if there is more than one reference, we don't need
|
||||
* to read that node to drop any references it has. We
|
||||
* just drop the ref we hold on that node and move on to the
|
||||
* next slot in this level.
|
||||
*/
|
||||
if (refs != 1) {
|
||||
parent = path->nodes[*level];
|
||||
root_owner = btrfs_header_owner(parent);
|
||||
root_gen = btrfs_header_generation(parent);
|
||||
path->slots[*level]++;
|
||||
|
||||
ret = btrfs_free_extent(trans, root, bytenr,
|
||||
blocksize, parent->start,
|
||||
root_owner, root_gen,
|
||||
*level - 1, 1);
|
||||
BUG_ON(ret);
|
||||
|
||||
atomic_inc(&root->fs_info->throttle_gen);
|
||||
wake_up(&root->fs_info->transaction_throttle);
|
||||
cond_resched();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* we need to keep freeing things in the next level down.
|
||||
* read the block and loop around to process it
|
||||
*/
|
||||
next = read_tree_block(root, bytenr, blocksize, ptr_gen);
|
||||
WARN_ON(*level <= 0);
|
||||
if (path->nodes[*level-1])
|
||||
free_extent_buffer(path->nodes[*level-1]);
|
||||
path->nodes[*level-1] = next;
|
||||
*level = btrfs_header_level(next);
|
||||
path->slots[*level] = 0;
|
||||
cond_resched();
|
||||
}
|
||||
out:
|
||||
WARN_ON(*level < 0);
|
||||
WARN_ON(*level >= BTRFS_MAX_LEVEL);
|
||||
|
||||
if (path->nodes[*level] == root->node) {
|
||||
parent = path->nodes[*level];
|
||||
bytenr = path->nodes[*level]->start;
|
||||
} else {
|
||||
parent = path->nodes[*level + 1];
|
||||
bytenr = btrfs_node_blockptr(parent, path->slots[*level + 1]);
|
||||
}
|
||||
|
||||
blocksize = btrfs_level_size(root, *level);
|
||||
root_owner = btrfs_header_owner(parent);
|
||||
root_gen = btrfs_header_generation(parent);
|
||||
|
||||
/*
|
||||
* cleanup and free the reference on the last node
|
||||
* we processed
|
||||
*/
|
||||
ret = btrfs_free_extent(trans, root, bytenr, blocksize,
|
||||
parent->start, root_owner, root_gen,
|
||||
*level, 1);
|
||||
free_extent_buffer(path->nodes[*level]);
|
||||
path->nodes[*level] = NULL;
|
||||
|
||||
*level += 1;
|
||||
BUG_ON(ret);
|
||||
|
||||
cond_resched();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct walk_control {
|
||||
u64 refs[BTRFS_MAX_LEVEL];
|
||||
u64 flags[BTRFS_MAX_LEVEL];
|
||||
@ -7129,288 +6705,6 @@ int btrfs_prepare_block_group_relocation(struct btrfs_root *root,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int __insert_orphan_inode(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
u64 objectid, u64 size)
|
||||
{
|
||||
struct btrfs_path *path;
|
||||
struct btrfs_inode_item *item;
|
||||
struct extent_buffer *leaf;
|
||||
int ret;
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
path->leave_spinning = 1;
|
||||
ret = btrfs_insert_empty_inode(trans, root, path, objectid);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
leaf = path->nodes[0];
|
||||
item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_inode_item);
|
||||
memset_extent_buffer(leaf, 0, (unsigned long)item, sizeof(*item));
|
||||
btrfs_set_inode_generation(leaf, item, 1);
|
||||
btrfs_set_inode_size(leaf, item, size);
|
||||
btrfs_set_inode_mode(leaf, item, S_IFREG | 0600);
|
||||
btrfs_set_inode_flags(leaf, item, BTRFS_INODE_NOCOMPRESS);
|
||||
btrfs_mark_buffer_dirty(leaf);
|
||||
btrfs_release_path(root, path);
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static noinline struct inode *create_reloc_inode(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_block_group_cache *group)
|
||||
{
|
||||
struct inode *inode = NULL;
|
||||
struct btrfs_trans_handle *trans;
|
||||
struct btrfs_root *root;
|
||||
struct btrfs_key root_key;
|
||||
u64 objectid = BTRFS_FIRST_FREE_OBJECTID;
|
||||
int err = 0;
|
||||
|
||||
root_key.objectid = BTRFS_DATA_RELOC_TREE_OBJECTID;
|
||||
root_key.type = BTRFS_ROOT_ITEM_KEY;
|
||||
root_key.offset = (u64)-1;
|
||||
root = btrfs_read_fs_root_no_name(fs_info, &root_key);
|
||||
if (IS_ERR(root))
|
||||
return ERR_CAST(root);
|
||||
|
||||
trans = btrfs_start_transaction(root, 1);
|
||||
BUG_ON(!trans);
|
||||
|
||||
err = btrfs_find_free_objectid(trans, root, objectid, &objectid);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = __insert_orphan_inode(trans, root, objectid, group->key.offset);
|
||||
BUG_ON(err);
|
||||
|
||||
err = btrfs_insert_file_extent(trans, root, objectid, 0, 0, 0,
|
||||
group->key.offset, 0, group->key.offset,
|
||||
0, 0, 0);
|
||||
BUG_ON(err);
|
||||
|
||||
inode = btrfs_iget_locked(root->fs_info->sb, objectid, root);
|
||||
if (inode->i_state & I_NEW) {
|
||||
BTRFS_I(inode)->root = root;
|
||||
BTRFS_I(inode)->location.objectid = objectid;
|
||||
BTRFS_I(inode)->location.type = BTRFS_INODE_ITEM_KEY;
|
||||
BTRFS_I(inode)->location.offset = 0;
|
||||
btrfs_read_locked_inode(inode);
|
||||
unlock_new_inode(inode);
|
||||
BUG_ON(is_bad_inode(inode));
|
||||
} else {
|
||||
BUG_ON(1);
|
||||
}
|
||||
BTRFS_I(inode)->index_cnt = group->key.objectid;
|
||||
|
||||
err = btrfs_orphan_add(trans, inode);
|
||||
out:
|
||||
btrfs_end_transaction(trans, root);
|
||||
if (err) {
|
||||
if (inode)
|
||||
iput(inode);
|
||||
inode = ERR_PTR(err);
|
||||
}
|
||||
return inode;
|
||||
}
|
||||
|
||||
int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len)
|
||||
{
|
||||
|
||||
struct btrfs_ordered_sum *sums;
|
||||
struct btrfs_sector_sum *sector_sum;
|
||||
struct btrfs_ordered_extent *ordered;
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
struct list_head list;
|
||||
size_t offset;
|
||||
int ret;
|
||||
u64 disk_bytenr;
|
||||
|
||||
INIT_LIST_HEAD(&list);
|
||||
|
||||
ordered = btrfs_lookup_ordered_extent(inode, file_pos);
|
||||
BUG_ON(ordered->file_offset != file_pos || ordered->len != len);
|
||||
|
||||
disk_bytenr = file_pos + BTRFS_I(inode)->index_cnt;
|
||||
ret = btrfs_lookup_csums_range(root->fs_info->csum_root, disk_bytenr,
|
||||
disk_bytenr + len - 1, &list);
|
||||
|
||||
while (!list_empty(&list)) {
|
||||
sums = list_entry(list.next, struct btrfs_ordered_sum, list);
|
||||
list_del_init(&sums->list);
|
||||
|
||||
sector_sum = sums->sums;
|
||||
sums->bytenr = ordered->start;
|
||||
|
||||
offset = 0;
|
||||
while (offset < sums->len) {
|
||||
sector_sum->bytenr += ordered->start - disk_bytenr;
|
||||
sector_sum++;
|
||||
offset += root->sectorsize;
|
||||
}
|
||||
|
||||
btrfs_add_ordered_sum(inode, ordered, sums);
|
||||
}
|
||||
btrfs_put_ordered_extent(ordered);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_relocate_block_group(struct btrfs_root *root, u64 group_start)
|
||||
{
|
||||
struct btrfs_trans_handle *trans;
|
||||
struct btrfs_path *path;
|
||||
struct btrfs_fs_info *info = root->fs_info;
|
||||
struct extent_buffer *leaf;
|
||||
struct inode *reloc_inode;
|
||||
struct btrfs_block_group_cache *block_group;
|
||||
struct btrfs_key key;
|
||||
u64 skipped;
|
||||
u64 cur_byte;
|
||||
u64 total_found;
|
||||
u32 nritems;
|
||||
int ret;
|
||||
int progress;
|
||||
int pass = 0;
|
||||
|
||||
root = root->fs_info->extent_root;
|
||||
|
||||
block_group = btrfs_lookup_block_group(info, group_start);
|
||||
BUG_ON(!block_group);
|
||||
|
||||
printk(KERN_INFO "btrfs relocating block group %llu flags %llu\n",
|
||||
(unsigned long long)block_group->key.objectid,
|
||||
(unsigned long long)block_group->flags);
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
BUG_ON(!path);
|
||||
|
||||
reloc_inode = create_reloc_inode(info, block_group);
|
||||
BUG_ON(IS_ERR(reloc_inode));
|
||||
|
||||
__alloc_chunk_for_shrink(root, block_group, 1);
|
||||
set_block_group_readonly(block_group);
|
||||
|
||||
btrfs_start_delalloc_inodes(info->tree_root);
|
||||
btrfs_wait_ordered_extents(info->tree_root, 0);
|
||||
again:
|
||||
skipped = 0;
|
||||
total_found = 0;
|
||||
progress = 0;
|
||||
key.objectid = block_group->key.objectid;
|
||||
key.offset = 0;
|
||||
key.type = 0;
|
||||
cur_byte = key.objectid;
|
||||
|
||||
trans = btrfs_start_transaction(info->tree_root, 1);
|
||||
btrfs_commit_transaction(trans, info->tree_root);
|
||||
|
||||
mutex_lock(&root->fs_info->cleaner_mutex);
|
||||
btrfs_clean_old_snapshots(info->tree_root);
|
||||
btrfs_remove_leaf_refs(info->tree_root, (u64)-1, 1);
|
||||
mutex_unlock(&root->fs_info->cleaner_mutex);
|
||||
|
||||
trans = btrfs_start_transaction(info->tree_root, 1);
|
||||
btrfs_commit_transaction(trans, info->tree_root);
|
||||
|
||||
while (1) {
|
||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
next:
|
||||
leaf = path->nodes[0];
|
||||
nritems = btrfs_header_nritems(leaf);
|
||||
if (path->slots[0] >= nritems) {
|
||||
ret = btrfs_next_leaf(root, path);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
if (ret == 1) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
leaf = path->nodes[0];
|
||||
nritems = btrfs_header_nritems(leaf);
|
||||
}
|
||||
|
||||
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
|
||||
|
||||
if (key.objectid >= block_group->key.objectid +
|
||||
block_group->key.offset)
|
||||
break;
|
||||
|
||||
if (progress && need_resched()) {
|
||||
btrfs_release_path(root, path);
|
||||
cond_resched();
|
||||
progress = 0;
|
||||
continue;
|
||||
}
|
||||
progress = 1;
|
||||
|
||||
if (btrfs_key_type(&key) != BTRFS_EXTENT_ITEM_KEY ||
|
||||
key.objectid + key.offset <= cur_byte) {
|
||||
path->slots[0]++;
|
||||
goto next;
|
||||
}
|
||||
|
||||
total_found++;
|
||||
cur_byte = key.objectid + key.offset;
|
||||
btrfs_release_path(root, path);
|
||||
|
||||
__alloc_chunk_for_shrink(root, block_group, 0);
|
||||
ret = relocate_one_extent(root, path, &key, block_group,
|
||||
reloc_inode, pass);
|
||||
BUG_ON(ret < 0);
|
||||
if (ret > 0)
|
||||
skipped++;
|
||||
|
||||
key.objectid = cur_byte;
|
||||
key.type = 0;
|
||||
key.offset = 0;
|
||||
}
|
||||
|
||||
btrfs_release_path(root, path);
|
||||
|
||||
if (pass == 0) {
|
||||
btrfs_wait_ordered_range(reloc_inode, 0, (u64)-1);
|
||||
invalidate_mapping_pages(reloc_inode->i_mapping, 0, -1);
|
||||
}
|
||||
|
||||
if (total_found > 0) {
|
||||
printk(KERN_INFO "btrfs found %llu extents in pass %d\n",
|
||||
(unsigned long long)total_found, pass);
|
||||
pass++;
|
||||
if (total_found == skipped && pass > 2) {
|
||||
iput(reloc_inode);
|
||||
reloc_inode = create_reloc_inode(info, block_group);
|
||||
pass = 0;
|
||||
}
|
||||
goto again;
|
||||
}
|
||||
|
||||
/* delete reloc_inode */
|
||||
iput(reloc_inode);
|
||||
|
||||
/* unpin extents in this range */
|
||||
trans = btrfs_start_transaction(info->tree_root, 1);
|
||||
btrfs_commit_transaction(trans, info->tree_root);
|
||||
|
||||
spin_lock(&block_group->lock);
|
||||
WARN_ON(block_group->pinned > 0);
|
||||
WARN_ON(block_group->reserved > 0);
|
||||
WARN_ON(btrfs_block_group_used(&block_group->item) > 0);
|
||||
spin_unlock(&block_group->lock);
|
||||
btrfs_put_block_group(block_group);
|
||||
ret = 0;
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* checks to see if its even possible to relocate this block group.
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user