diff options
Diffstat (limited to 'fs/btrfs/extent-tree.c')
| -rw-r--r-- | fs/btrfs/extent-tree.c | 77 | 
1 files changed, 61 insertions, 16 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 66bac226944..f5be06a2462 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -1782,6 +1782,9 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,  		for (i = 0; i < multi->num_stripes; i++, stripe++) { +			if (!stripe->dev->can_discard) +				continue; +  			ret = btrfs_issue_discard(stripe->dev->bdev,  						  stripe->physical,  						  stripe->length); @@ -1789,11 +1792,16 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,  				discarded_bytes += stripe->length;  			else if (ret != -EOPNOTSUPP)  				break; + +			/* +			 * Just in case we get back EOPNOTSUPP for some reason, +			 * just ignore the return value so we don't screw up +			 * people calling discard_extent. +			 */ +			ret = 0;  		}  		kfree(multi);  	} -	if (discarded_bytes && ret == -EOPNOTSUPP) -		ret = 0;  	if (actual_bytes)  		*actual_bytes = discarded_bytes; @@ -6269,8 +6277,8 @@ static noinline int walk_up_tree(struct btrfs_trans_handle *trans,   * also make sure backrefs for the shared block and all lower level   * blocks are properly updated.   */ -int btrfs_drop_snapshot(struct btrfs_root *root, -			struct btrfs_block_rsv *block_rsv, int update_ref) +void btrfs_drop_snapshot(struct btrfs_root *root, +			 struct btrfs_block_rsv *block_rsv, int update_ref)  {  	struct btrfs_path *path;  	struct btrfs_trans_handle *trans; @@ -6283,13 +6291,16 @@ int btrfs_drop_snapshot(struct btrfs_root *root,  	int level;  	path = btrfs_alloc_path(); -	if (!path) -		return -ENOMEM; +	if (!path) { +		err = -ENOMEM; +		goto out; +	}  	wc = kzalloc(sizeof(*wc), GFP_NOFS);  	if (!wc) {  		btrfs_free_path(path); -		return -ENOMEM; +		err = -ENOMEM; +		goto out;  	}  	trans = btrfs_start_transaction(tree_root, 0); @@ -6318,7 +6329,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root,  		path->lowest_level = 0;  		if (ret < 0) {  			err = ret; -			goto out; +			goto out_free;  		}  		WARN_ON(ret > 0); @@ -6425,11 +6436,14 @@ int btrfs_drop_snapshot(struct btrfs_root *root,  		free_extent_buffer(root->commit_root);  		kfree(root);  	} -out: +out_free:  	btrfs_end_transaction_throttle(trans, tree_root);  	kfree(wc);  	btrfs_free_path(path); -	return err; +out: +	if (err) +		btrfs_std_error(root->fs_info, err); +	return;  }  /* @@ -6720,6 +6734,10 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)  	struct btrfs_space_info *space_info;  	struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;  	struct btrfs_device *device; +	u64 min_free; +	u64 dev_min = 1; +	u64 dev_nr = 0; +	int index;  	int full = 0;  	int ret = 0; @@ -6729,8 +6747,10 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)  	if (!block_group)  		return -1; +	min_free = btrfs_block_group_used(&block_group->item); +  	/* no bytes used, we're good */ -	if (!btrfs_block_group_used(&block_group->item)) +	if (!min_free)  		goto out;  	space_info = block_group->space_info; @@ -6746,10 +6766,9 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)  	 * all of the extents from this block group.  If we can, we're good  	 */  	if ((space_info->total_bytes != block_group->key.offset) && -	   (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)) { +	    (space_info->bytes_used + space_info->bytes_reserved + +	     space_info->bytes_pinned + space_info->bytes_readonly + +	     min_free < space_info->total_bytes)) {  		spin_unlock(&space_info->lock);  		goto out;  	} @@ -6766,9 +6785,31 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)  	if (full)  		goto out; +	/* +	 * index: +	 *      0: raid10 +	 *      1: raid1 +	 *      2: dup +	 *      3: raid0 +	 *      4: single +	 */ +	index = get_block_group_index(block_group); +	if (index == 0) { +		dev_min = 4; +		/* Divide by 2 */ +		min_free >>= 1; +	} else if (index == 1) { +		dev_min = 2; +	} else if (index == 2) { +		/* Multiply by 2 */ +		min_free <<= 1; +	} else if (index == 3) { +		dev_min = fs_devices->rw_devices; +		do_div(min_free, dev_min); +	} +  	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;  		/* @@ -6779,7 +6820,11 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)  			ret = find_free_dev_extent(NULL, device, min_free,  						   &dev_offset, NULL);  			if (!ret) +				dev_nr++; + +			if (dev_nr >= dev_min)  				break; +  			ret = -1;  		}  	}  |