diff options
Diffstat (limited to 'fs/btrfs/relocation.c')
| -rw-r--r-- | fs/btrfs/relocation.c | 363 | 
1 files changed, 187 insertions, 176 deletions
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index aacc2121e87..65245a07275 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -94,6 +94,7 @@ struct backref_edge {  #define LOWER	0  #define UPPER	1 +#define RELOCATION_RESERVED_NODES	256  struct backref_cache {  	/* red black tree of all backref nodes in the cache */ @@ -176,6 +177,8 @@ struct reloc_control {  	u64 merging_rsv_size;  	/* size of relocated tree nodes */  	u64 nodes_relocated; +	/* reserved size for block group relocation*/ +	u64 reserved_bytes;  	u64 search_start;  	u64 extents_found; @@ -184,7 +187,6 @@ struct reloc_control {  	unsigned int create_reloc_tree:1;  	unsigned int merge_reloc_tree:1;  	unsigned int found_file_extent:1; -	unsigned int commit_transaction:1;  };  /* stages of data relocation */ @@ -335,7 +337,7 @@ static void backref_tree_panic(struct rb_node *rb_node, int errno, u64 bytenr)  	if (bnode->root)  		fs_info = bnode->root->fs_info;  	btrfs_panic(fs_info, errno, "Inconsistency in backref cache " -		    "found at offset %llu\n", bytenr); +		    "found at offset %llu", bytenr);  }  /* @@ -526,7 +528,7 @@ static int should_ignore_root(struct btrfs_root *root)  {  	struct btrfs_root *reloc_root; -	if (!root->ref_cows) +	if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state))  		return 0;  	reloc_root = root->reloc_root; @@ -571,7 +573,9 @@ static int is_cowonly_root(u64 root_objectid)  	    root_objectid == BTRFS_CHUNK_TREE_OBJECTID ||  	    root_objectid == BTRFS_DEV_TREE_OBJECTID ||  	    root_objectid == BTRFS_TREE_LOG_OBJECTID || -	    root_objectid == BTRFS_CSUM_TREE_OBJECTID) +	    root_objectid == BTRFS_CSUM_TREE_OBJECTID || +	    root_objectid == BTRFS_UUID_TREE_OBJECTID || +	    root_objectid == BTRFS_QUOTA_TREE_OBJECTID)  		return 1;  	return 0;  } @@ -588,7 +592,7 @@ static struct btrfs_root *read_fs_root(struct btrfs_fs_info *fs_info,  	else  		key.offset = (u64)-1; -	return btrfs_read_fs_root_no_name(fs_info, &key); +	return btrfs_get_fs_root(fs_info, &key, false);  }  #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 @@ -606,7 +610,7 @@ struct btrfs_root *find_tree_root(struct reloc_control *rc,  	root = read_fs_root(rc->extent_root->fs_info, root_objectid);  	BUG_ON(IS_ERR(root)); -	if (root->ref_cows && +	if (test_bit(BTRFS_ROOT_REF_COWS, &root->state) &&  	    generation != btrfs_root_generation(&root->root_item))  		return NULL; @@ -883,7 +887,7 @@ again:  			goto out;  		} -		if (!root->ref_cows) +		if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state))  			cur->cowonly = 1;  		if (btrfs_root_level(&root->root_item) == cur->level) { @@ -950,7 +954,8 @@ again:  				upper->bytenr = eb->start;  				upper->owner = btrfs_header_owner(eb);  				upper->level = lower->level + 1; -				if (!root->ref_cows) +				if (!test_bit(BTRFS_ROOT_REF_COWS, +					      &root->state))  					upper->cowonly = 1;  				/* @@ -1254,7 +1259,7 @@ static int __must_check __add_reloc_root(struct btrfs_root *root)  	if (rb_node) {  		btrfs_panic(root->fs_info, -EEXIST, "Duplicate root found "  			    "for start=%llu while inserting into relocation " -			    "tree\n", node->bytenr); +			    "tree", node->bytenr);  		kfree(node);  		return -EEXIST;  	} @@ -1264,10 +1269,10 @@ static int __must_check __add_reloc_root(struct btrfs_root *root)  }  /* - * helper to update/delete the 'address of tree root -> reloc tree' + * helper to delete the 'address of tree root -> reloc tree'   * mapping   */ -static int __update_reloc_root(struct btrfs_root *root, int del) +static void __del_reloc_root(struct btrfs_root *root)  {  	struct rb_node *rb_node;  	struct mapping_node *node = NULL; @@ -1275,7 +1280,7 @@ static int __update_reloc_root(struct btrfs_root *root, int del)  	spin_lock(&rc->reloc_root_tree.lock);  	rb_node = tree_search(&rc->reloc_root_tree.rb_root, -			      root->commit_root->start); +			      root->node->start);  	if (rb_node) {  		node = rb_entry(rb_node, struct mapping_node, rb_node);  		rb_erase(&node->rb_node, &rc->reloc_root_tree.rb_root); @@ -1283,23 +1288,45 @@ static int __update_reloc_root(struct btrfs_root *root, int del)  	spin_unlock(&rc->reloc_root_tree.lock);  	if (!node) -		return 0; +		return;  	BUG_ON((struct btrfs_root *)node->data != root); -	if (!del) { -		spin_lock(&rc->reloc_root_tree.lock); -		node->bytenr = root->node->start; -		rb_node = tree_insert(&rc->reloc_root_tree.rb_root, -				      node->bytenr, &node->rb_node); -		spin_unlock(&rc->reloc_root_tree.lock); -		if (rb_node) -			backref_tree_panic(rb_node, -EEXIST, node->bytenr); -	} else { -		spin_lock(&root->fs_info->trans_lock); -		list_del_init(&root->root_list); -		spin_unlock(&root->fs_info->trans_lock); -		kfree(node); +	spin_lock(&root->fs_info->trans_lock); +	list_del_init(&root->root_list); +	spin_unlock(&root->fs_info->trans_lock); +	kfree(node); +} + +/* + * helper to update the 'address of tree root -> reloc tree' + * mapping + */ +static int __update_reloc_root(struct btrfs_root *root, u64 new_bytenr) +{ +	struct rb_node *rb_node; +	struct mapping_node *node = NULL; +	struct reloc_control *rc = root->fs_info->reloc_ctl; + +	spin_lock(&rc->reloc_root_tree.lock); +	rb_node = tree_search(&rc->reloc_root_tree.rb_root, +			      root->node->start); +	if (rb_node) { +		node = rb_entry(rb_node, struct mapping_node, rb_node); +		rb_erase(&node->rb_node, &rc->reloc_root_tree.rb_root);  	} +	spin_unlock(&rc->reloc_root_tree.lock); + +	if (!node) +		return 0; +	BUG_ON((struct btrfs_root *)node->data != root); + +	spin_lock(&rc->reloc_root_tree.lock); +	node->bytenr = new_bytenr; +	rb_node = tree_insert(&rc->reloc_root_tree.rb_root, +			      node->bytenr, &node->rb_node); +	spin_unlock(&rc->reloc_root_tree.lock); +	if (rb_node) +		backref_tree_panic(rb_node, -EEXIST, node->bytenr);  	return 0;  } @@ -1383,6 +1410,7 @@ int btrfs_init_reloc_root(struct btrfs_trans_handle *trans,  {  	struct btrfs_root *reloc_root;  	struct reloc_control *rc = root->fs_info->reloc_ctl; +	struct btrfs_block_rsv *rsv;  	int clear_rsv = 0;  	int ret; @@ -1396,13 +1424,14 @@ int btrfs_init_reloc_root(struct btrfs_trans_handle *trans,  	    root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID)  		return 0; -	if (!trans->block_rsv) { +	if (!trans->reloc_reserved) { +		rsv = trans->block_rsv;  		trans->block_rsv = rc->block_rsv;  		clear_rsv = 1;  	}  	reloc_root = create_reloc_root(trans, root, root->root_key.objectid);  	if (clear_rsv) -		trans->block_rsv = NULL; +		trans->block_rsv = rsv;  	ret = __add_reloc_root(reloc_root);  	BUG_ON(ret < 0); @@ -1418,7 +1447,6 @@ int btrfs_update_reloc_root(struct btrfs_trans_handle *trans,  {  	struct btrfs_root *reloc_root;  	struct btrfs_root_item *root_item; -	int del = 0;  	int ret;  	if (!root->reloc_root) @@ -1430,11 +1458,9 @@ int btrfs_update_reloc_root(struct btrfs_trans_handle *trans,  	if (root->fs_info->reloc_ctl->merge_reloc_tree &&  	    btrfs_root_refs(root_item) == 0) {  		root->reloc_root = NULL; -		del = 1; +		__del_reloc_root(reloc_root);  	} -	__update_reloc_root(reloc_root, del); -  	if (reloc_root->commit_root != reloc_root->node) {  		btrfs_set_root_node(root_item, reloc_root->node);  		free_extent_buffer(reloc_root->commit_root); @@ -1548,7 +1574,7 @@ static int get_new_location(struct inode *reloc_inode, u64 *new_bytenr,  	       btrfs_file_extent_other_encoding(leaf, fi));  	if (num_bytes != btrfs_file_extent_disk_num_bytes(leaf, fi)) { -		ret = 1; +		ret = -EINVAL;  		goto out;  	} @@ -1579,7 +1605,7 @@ int replace_file_extents(struct btrfs_trans_handle *trans,  	u64 end;  	u32 nritems;  	u32 i; -	int ret; +	int ret = 0;  	int first = 1;  	int dirty = 0; @@ -1642,11 +1668,13 @@ int replace_file_extents(struct btrfs_trans_handle *trans,  		ret = get_new_location(rc->data_inode, &new_bytenr,  				       bytenr, num_bytes); -		if (ret > 0) { -			WARN_ON(1); -			continue; +		if (ret) { +			/* +			 * Don't have to abort since we've not changed anything +			 * in the file extent yet. +			 */ +			break;  		} -		BUG_ON(ret < 0);  		btrfs_set_file_extent_disk_bytenr(leaf, fi, new_bytenr);  		dirty = 1; @@ -1656,18 +1684,24 @@ int replace_file_extents(struct btrfs_trans_handle *trans,  					   num_bytes, parent,  					   btrfs_header_owner(leaf),  					   key.objectid, key.offset, 1); -		BUG_ON(ret); +		if (ret) { +			btrfs_abort_transaction(trans, root, ret); +			break; +		}  		ret = btrfs_free_extent(trans, root, bytenr, num_bytes,  					parent, btrfs_header_owner(leaf),  					key.objectid, key.offset, 1); -		BUG_ON(ret); +		if (ret) { +			btrfs_abort_transaction(trans, root, ret); +			break; +		}  	}  	if (dirty)  		btrfs_mark_buffer_dirty(leaf);  	if (inode)  		btrfs_add_delayed_iput(inode); -	return 0; +	return ret;  }  static noinline_for_stack @@ -1767,8 +1801,7 @@ again:  			new_ptr_gen = 0;  		} -		if (new_bytenr > 0 && new_bytenr == old_bytenr) { -			WARN_ON(1); +		if (WARN_ON(new_bytenr > 0 && new_bytenr == old_bytenr)) {  			ret = level;  			break;  		} @@ -2050,7 +2083,7 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,  	LIST_HEAD(inode_list);  	struct btrfs_key key;  	struct btrfs_key next_key; -	struct btrfs_trans_handle *trans; +	struct btrfs_trans_handle *trans = NULL;  	struct btrfs_root *reloc_root;  	struct btrfs_root_item *root_item;  	struct btrfs_path *path; @@ -2099,18 +2132,19 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,  	memset(&next_key, 0, sizeof(next_key));  	while (1) { -		trans = btrfs_start_transaction(root, 0); -		BUG_ON(IS_ERR(trans)); -		trans->block_rsv = rc->block_rsv; -  		ret = btrfs_block_rsv_refill(root, rc->block_rsv, min_reserved,  					     BTRFS_RESERVE_FLUSH_ALL);  		if (ret) { -			BUG_ON(ret != -EAGAIN); -			ret = btrfs_commit_transaction(trans, root); -			BUG_ON(ret); -			continue; +			err = ret; +			goto out;  		} +		trans = btrfs_start_transaction(root, 0); +		if (IS_ERR(trans)) { +			err = PTR_ERR(trans); +			trans = NULL; +			goto out; +		} +		trans->block_rsv = rc->block_rsv;  		replaced = 0;  		max_level = level; @@ -2156,6 +2190,7 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,  		root_item->drop_level = level;  		btrfs_end_transaction_throttle(trans, root); +		trans = NULL;  		btrfs_btree_balance_dirty(root); @@ -2184,7 +2219,8 @@ out:  		btrfs_update_reloc_root(trans, root);  	} -	btrfs_end_transaction_throttle(trans, root); +	if (trans) +		btrfs_end_transaction_throttle(trans, root);  	btrfs_btree_balance_dirty(root); @@ -2275,17 +2311,13 @@ void free_reloc_roots(struct list_head *list)  	while (!list_empty(list)) {  		reloc_root = list_entry(list->next, struct btrfs_root,  					root_list); -		__update_reloc_root(reloc_root, 1); -		free_extent_buffer(reloc_root->node); -		free_extent_buffer(reloc_root->commit_root); -		kfree(reloc_root); +		__del_reloc_root(reloc_root);  	}  }  static noinline_for_stack  int merge_reloc_roots(struct reloc_control *rc)  { -	struct btrfs_trans_handle *trans;  	struct btrfs_root *root;  	struct btrfs_root *reloc_root;  	u64 last_snap; @@ -2320,10 +2352,9 @@ again:  			ret = merge_reloc_root(rc, root);  			if (ret) { -				__update_reloc_root(reloc_root, 1); -				free_extent_buffer(reloc_root->node); -				free_extent_buffer(reloc_root->commit_root); -				kfree(reloc_root); +				if (list_empty(&reloc_root->root_list)) +					list_add_tail(&reloc_root->root_list, +						      &reloc_roots);  				goto out;  			}  		} else { @@ -2344,26 +2375,6 @@ again:  				list_add_tail(&reloc_root->root_list,  					      &reloc_roots);  			goto out; -		} else if (!ret) { -			/* -			 * recover the last snapshot tranid to avoid -			 * the space balance break NOCOW. -			 */ -			root = read_fs_root(rc->extent_root->fs_info, -					    objectid); -			if (IS_ERR(root)) -				continue; - -			trans = btrfs_join_transaction(root); -			BUG_ON(IS_ERR(trans)); - -			/* Check if the fs/file tree was snapshoted or not. */ -			if (btrfs_root_last_snapshot(&root->root_item) == -			    otransid - 1) -				btrfs_set_root_last_snapshot(&root->root_item, -							     last_snap); -				 -			btrfs_end_transaction(trans, root);  		}  	} @@ -2376,6 +2387,13 @@ out:  		btrfs_std_error(root->fs_info, ret);  		if (!list_empty(&reloc_roots))  			free_reloc_roots(&reloc_roots); + +		/* new reloc root may be added */ +		mutex_lock(&root->fs_info->reloc_mutex); +		list_splice_init(&rc->reloc_roots, &reloc_roots); +		mutex_unlock(&root->fs_info->reloc_mutex); +		if (!list_empty(&reloc_roots)) +			free_reloc_roots(&reloc_roots);  	}  	BUG_ON(!RB_EMPTY_ROOT(&rc->reloc_root_tree.rb_root)); @@ -2412,7 +2430,7 @@ static noinline_for_stack  struct btrfs_root *select_reloc_root(struct btrfs_trans_handle *trans,  				     struct reloc_control *rc,  				     struct backref_node *node, -				     struct backref_edge *edges[], int *nr) +				     struct backref_edge *edges[])  {  	struct backref_node *next;  	struct btrfs_root *root; @@ -2424,7 +2442,7 @@ struct btrfs_root *select_reloc_root(struct btrfs_trans_handle *trans,  		next = walk_up_backref(next, edges, &index);  		root = next->root;  		BUG_ON(!root); -		BUG_ON(!root->ref_cows); +		BUG_ON(!test_bit(BTRFS_ROOT_REF_COWS, &root->state));  		if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) {  			record_reloc_root_in_trans(trans, root); @@ -2454,7 +2472,6 @@ struct btrfs_root *select_reloc_root(struct btrfs_trans_handle *trans,  	if (!root)  		return NULL; -	*nr = index;  	next = node;  	/* setup backref node path for btrfs_reloc_cow_block */  	while (1) { @@ -2490,7 +2507,7 @@ struct btrfs_root *select_one_root(struct btrfs_trans_handle *trans,  		BUG_ON(!root);  		/* no other choice for non-references counted tree */ -		if (!root->ref_cows) +		if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state))  			return root;  		if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID) @@ -2550,28 +2567,36 @@ static int reserve_metadata_space(struct btrfs_trans_handle *trans,  	struct btrfs_root *root = rc->extent_root;  	u64 num_bytes;  	int ret; +	u64 tmp;  	num_bytes = calcu_metadata_size(rc, node, 1) * 2;  	trans->block_rsv = rc->block_rsv; -	ret = btrfs_block_rsv_add(root, rc->block_rsv, num_bytes, -				  BTRFS_RESERVE_FLUSH_ALL); +	rc->reserved_bytes += num_bytes; +	ret = btrfs_block_rsv_refill(root, rc->block_rsv, num_bytes, +				BTRFS_RESERVE_FLUSH_ALL);  	if (ret) { -		if (ret == -EAGAIN) -			rc->commit_transaction = 1; +		if (ret == -EAGAIN) { +			tmp = rc->extent_root->nodesize * +				RELOCATION_RESERVED_NODES; +			while (tmp <= rc->reserved_bytes) +				tmp <<= 1; +			/* +			 * only one thread can access block_rsv at this point, +			 * so we don't need hold lock to protect block_rsv. +			 * we expand more reservation size here to allow enough +			 * space for relocation and we will return eailer in +			 * enospc case. +			 */ +			rc->block_rsv->size = tmp + rc->extent_root->nodesize * +					      RELOCATION_RESERVED_NODES; +		}  		return ret;  	}  	return 0;  } -static void release_metadata_space(struct reloc_control *rc, -				   struct backref_node *node) -{ -	u64 num_bytes = calcu_metadata_size(rc, node, 0) * 2; -	btrfs_block_rsv_release(rc->extent_root, rc->block_rsv, num_bytes); -} -  /*   * relocate a block tree, and then update pointers in upper level   * blocks that reference the block to point to the new location. @@ -2593,7 +2618,6 @@ static int do_relocation(struct btrfs_trans_handle *trans,  	u32 blocksize;  	u64 bytenr;  	u64 generation; -	int nr;  	int slot;  	int ret;  	int err = 0; @@ -2606,7 +2630,7 @@ static int do_relocation(struct btrfs_trans_handle *trans,  		cond_resched();  		upper = edge->node[UPPER]; -		root = select_reloc_root(trans, rc, upper, edges, &nr); +		root = select_reloc_root(trans, rc, upper, edges);  		BUG_ON(!root);  		if (upper->eb && !upper->locked) { @@ -2858,7 +2882,6 @@ static int relocate_tree_block(struct btrfs_trans_handle *trans,  				struct btrfs_path *path)  {  	struct btrfs_root *root; -	int release = 0;  	int ret = 0;  	if (!node) @@ -2871,15 +2894,14 @@ static int relocate_tree_block(struct btrfs_trans_handle *trans,  		goto out;  	} -	if (!root || root->ref_cows) { +	if (!root || test_bit(BTRFS_ROOT_REF_COWS, &root->state)) {  		ret = reserve_metadata_space(trans, rc, node);  		if (ret)  			goto out; -		release = 1;  	}  	if (root) { -		if (root->ref_cows) { +		if (test_bit(BTRFS_ROOT_REF_COWS, &root->state)) {  			BUG_ON(node->new_bytenr);  			BUG_ON(!list_empty(&node->list));  			btrfs_record_root_in_trans(trans, root); @@ -2900,11 +2922,8 @@ static int relocate_tree_block(struct btrfs_trans_handle *trans,  		ret = do_relocation(trans, rc, node, key, path, 1);  	}  out: -	if (ret || node->level == 0 || node->cowonly) { -		if (release) -			release_metadata_space(rc, node); +	if (ret || node->level == 0 || node->cowonly)  		remove_backref_node(&rc->backref_cache, node); -	}  	return ret;  } @@ -3250,7 +3269,7 @@ static int add_tree_block(struct reloc_control *rc,  	struct rb_node *rb_node;  	u32 item_size;  	int level = -1; -	int generation; +	u64 generation;  	eb =  path->nodes[0];  	item_size = btrfs_item_size_nr(eb, path->slots[0]); @@ -3399,7 +3418,6 @@ static int delete_block_group_cache(struct btrfs_fs_info *fs_info,  				    struct inode *inode, u64 ino)  {  	struct btrfs_key key; -	struct btrfs_path *path;  	struct btrfs_root *root = fs_info->tree_root;  	struct btrfs_trans_handle *trans;  	int ret = 0; @@ -3424,22 +3442,14 @@ truncate:  	if (ret)  		goto out; -	path = btrfs_alloc_path(); -	if (!path) { -		ret = -ENOMEM; -		goto out; -	} -  	trans = btrfs_join_transaction(root);  	if (IS_ERR(trans)) { -		btrfs_free_path(path);  		ret = PTR_ERR(trans);  		goto out;  	} -	ret = btrfs_truncate_free_space_cache(root, trans, path, inode); +	ret = btrfs_truncate_free_space_cache(root, trans, inode); -	btrfs_free_path(path);  	btrfs_end_transaction(trans, root);  	btrfs_btree_balance_dirty(root);  out: @@ -3541,10 +3551,8 @@ static int find_data_references(struct reloc_control *rc,  				err = ret;  				goto out;  			} -			if (ret > 0) { -				WARN_ON(1); +			if (WARN_ON(ret > 0))  				goto out; -			}  			leaf = path->nodes[0];  			nritems = btrfs_header_nritems(leaf); @@ -3564,11 +3572,9 @@ static int find_data_references(struct reloc_control *rc,  		}  		btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); -		if (key.objectid != ref_objectid || -		    key.type != BTRFS_EXTENT_DATA_KEY) { -			WARN_ON(1); +		if (WARN_ON(key.objectid != ref_objectid || +		    key.type != BTRFS_EXTENT_DATA_KEY))  			break; -		}  		fi = btrfs_item_ptr(leaf, path->slots[0],  				    struct btrfs_file_extent_item); @@ -3840,29 +3846,20 @@ static noinline_for_stack  int prepare_to_relocate(struct reloc_control *rc)  {  	struct btrfs_trans_handle *trans; -	int ret;  	rc->block_rsv = btrfs_alloc_block_rsv(rc->extent_root,  					      BTRFS_BLOCK_RSV_TEMP);  	if (!rc->block_rsv)  		return -ENOMEM; -	/* -	 * reserve some space for creating reloc trees. -	 * btrfs_init_reloc_root will use them when there -	 * is no reservation in transaction handle. -	 */ -	ret = btrfs_block_rsv_add(rc->extent_root, rc->block_rsv, -				  rc->extent_root->nodesize * 256, -				  BTRFS_RESERVE_FLUSH_ALL); -	if (ret) -		return ret; -  	memset(&rc->cluster, 0, sizeof(rc->cluster));  	rc->search_start = rc->block_group->key.objectid;  	rc->extents_found = 0;  	rc->nodes_relocated = 0;  	rc->merging_rsv_size = 0; +	rc->reserved_bytes = 0; +	rc->block_rsv->size = rc->extent_root->nodesize * +			      RELOCATION_RESERVED_NODES;  	rc->create_reloc_tree = 1;  	set_reloc_control(rc); @@ -3906,6 +3903,14 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc)  	}  	while (1) { +		rc->reserved_bytes = 0; +		ret = btrfs_block_rsv_refill(rc->extent_root, +					rc->block_rsv, rc->block_rsv->size, +					BTRFS_RESERVE_FLUSH_ALL); +		if (ret) { +			err = ret; +			break; +		}  		progress++;  		trans = btrfs_start_transaction(rc->extent_root, 0);  		if (IS_ERR(trans)) { @@ -3984,6 +3989,12 @@ restart:  		if (!RB_EMPTY_ROOT(&blocks)) {  			ret = relocate_tree_blocks(trans, rc, &blocks);  			if (ret < 0) { +				/* +				 * if we fail to relocate tree blocks, force to update +				 * backref cache when committing transaction. +				 */ +				rc->backref_cache.last_trans = trans->transid - 1; +  				if (ret != -EAGAIN) {  					err = ret;  					break; @@ -3993,24 +4004,8 @@ restart:  			}  		} -		ret = btrfs_block_rsv_check(rc->extent_root, rc->block_rsv, 5); -		if (ret < 0) { -			if (ret != -ENOSPC) { -				err = ret; -				WARN_ON(1); -				break; -			} -			rc->commit_transaction = 1; -		} - -		if (rc->commit_transaction) { -			rc->commit_transaction = 0; -			ret = btrfs_commit_transaction(trans, rc->extent_root); -			BUG_ON(ret); -		} else { -			btrfs_end_transaction_throttle(trans, rc->extent_root); -			btrfs_btree_balance_dirty(rc->extent_root); -		} +		btrfs_end_transaction_throttle(trans, rc->extent_root); +		btrfs_btree_balance_dirty(rc->extent_root);  		trans = NULL;  		if (rc->stage == MOVE_DATA_EXTENTS && @@ -4230,15 +4225,15 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)  		goto out;  	} -	printk(KERN_INFO "btrfs: relocating block group %llu flags %llu\n", +	btrfs_info(extent_root->fs_info, "relocating block group %llu flags %llu",  	       rc->block_group->key.objectid, rc->block_group->flags); -	ret = btrfs_start_all_delalloc_inodes(fs_info, 0); +	ret = btrfs_start_delalloc_roots(fs_info, 0, -1);  	if (ret < 0) {  		err = ret;  		goto out;  	} -	btrfs_wait_all_ordered_extents(fs_info, 0); +	btrfs_wait_ordered_roots(fs_info, -1);  	while (1) {  		mutex_lock(&fs_info->cleaner_mutex); @@ -4252,22 +4247,22 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)  		if (rc->extents_found == 0)  			break; -		printk(KERN_INFO "btrfs: found %llu extents\n", +		btrfs_info(extent_root->fs_info, "found %llu extents",  			rc->extents_found);  		if (rc->stage == MOVE_DATA_EXTENTS && rc->found_file_extent) { -			btrfs_wait_ordered_range(rc->data_inode, 0, (u64)-1); +			ret = btrfs_wait_ordered_range(rc->data_inode, 0, +						       (u64)-1); +			if (ret) { +				err = ret; +				goto out; +			}  			invalidate_mapping_pages(rc->data_inode->i_mapping,  						 0, -1);  			rc->stage = UPDATE_DATA_PTRS;  		}  	} -	filemap_write_and_wait_range(fs_info->btree_inode->i_mapping, -				     rc->block_group->key.objectid, -				     rc->block_group->key.objectid + -				     rc->block_group->key.offset - 1); -  	WARN_ON(rc->block_group->pinned > 0);  	WARN_ON(rc->block_group->reserved > 0);  	WARN_ON(btrfs_block_group_used(&rc->block_group->item) > 0); @@ -4473,6 +4468,7 @@ int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len)  	struct btrfs_root *root = BTRFS_I(inode)->root;  	int ret;  	u64 disk_bytenr; +	u64 new_bytenr;  	LIST_HEAD(list);  	ordered = btrfs_lookup_ordered_extent(inode, file_pos); @@ -4484,13 +4480,24 @@ int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len)  	if (ret)  		goto out; -	disk_bytenr = ordered->start;  	while (!list_empty(&list)) {  		sums = list_entry(list.next, struct btrfs_ordered_sum, list);  		list_del_init(&sums->list); -		sums->bytenr = disk_bytenr; -		disk_bytenr += sums->len; +		/* +		 * We need to offset the new_bytenr based on where the csum is. +		 * We need to do this because we will read in entire prealloc +		 * extents but we may have written to say the middle of the +		 * prealloc extent, so we need to make sure the csum goes with +		 * the right disk offset. +		 * +		 * We can do this because the data reloc inode refers strictly +		 * to the on disk bytes, so we don't have to worry about +		 * disk_len vs real len like with real inodes since it's all +		 * disk length. +		 */ +		new_bytenr = ordered->start + (sums->bytenr - disk_bytenr); +		sums->bytenr = new_bytenr;  		btrfs_add_ordered_sum(inode, ordered, sums);  	} @@ -4499,23 +4506,28 @@ out:  	return ret;  } -void btrfs_reloc_cow_block(struct btrfs_trans_handle *trans, -			   struct btrfs_root *root, struct extent_buffer *buf, -			   struct extent_buffer *cow) +int btrfs_reloc_cow_block(struct btrfs_trans_handle *trans, +			  struct btrfs_root *root, struct extent_buffer *buf, +			  struct extent_buffer *cow)  {  	struct reloc_control *rc;  	struct backref_node *node;  	int first_cow = 0;  	int level; -	int ret; +	int ret = 0;  	rc = root->fs_info->reloc_ctl;  	if (!rc) -		return; +		return 0;  	BUG_ON(rc->stage == UPDATE_DATA_PTRS &&  	       root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID); +	if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) { +		if (buf == root->node) +			__update_reloc_root(root, cow->start); +	} +  	level = btrfs_header_level(buf);  	if (btrfs_header_generation(buf) <=  	    btrfs_root_last_snapshot(&root->root_item)) @@ -4547,10 +4559,9 @@ void btrfs_reloc_cow_block(struct btrfs_trans_handle *trans,  			rc->nodes_relocated += buf->len;  	} -	if (level == 0 && first_cow && rc->stage == UPDATE_DATA_PTRS) { +	if (level == 0 && first_cow && rc->stage == UPDATE_DATA_PTRS)  		ret = replace_file_extents(trans, rc, root, cow); -		BUG_ON(ret); -	} +	return ret;  }  /*  | 
