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:
@@ -4462,430 +4462,6 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
|||||||
return buf;
|
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 {
|
struct walk_control {
|
||||||
u64 refs[BTRFS_MAX_LEVEL];
|
u64 refs[BTRFS_MAX_LEVEL];
|
||||||
u64 flags[BTRFS_MAX_LEVEL];
|
u64 flags[BTRFS_MAX_LEVEL];
|
||||||
@@ -7129,288 +6705,6 @@ int btrfs_prepare_block_group_relocation(struct btrfs_root *root,
|
|||||||
return 0;
|
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.
|
* checks to see if its even possible to relocate this block group.
|
||||||
*
|
*
|
||||||
|
Reference in New Issue
Block a user