Commit 5378e607 authored by Li Dongyang's avatar Li Dongyang Committed by root
Browse files

Btrfs: adjust btrfs_discard_extent() return errors and trimmed bytes



Callers of btrfs_discard_extent() should check if we are mounted with -o discard,
as we want to make fitrim to work even the fs is not mounted with -o discard.
Also we should use REQ_DISCARD to map the free extent to get a full mapping,
last we only return errors if
1. the error is not a EOPNOTSUPP
2. no device supports discard

Signed-off-by: default avatarLi Dongyang <lidongyang@novell.com>
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent fce3bb9a
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -2229,7 +2229,7 @@ u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo);
int btrfs_error_unpin_extent_range(struct btrfs_root *root,
int btrfs_error_unpin_extent_range(struct btrfs_root *root,
				   u64 start, u64 end);
				   u64 start, u64 end);
int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr,
int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr,
			       u64 num_bytes);
			       u64 num_bytes, u64 *actual_bytes);
int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans,
int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans,
			    struct btrfs_root *root, u64 type);
			    struct btrfs_root *root, u64 type);


+4 −1
Original line number Original line Diff line number Diff line
@@ -3054,7 +3054,10 @@ static int btrfs_destroy_pinned_extent(struct btrfs_root *root,
			break;
			break;


		/* opt_discard */
		/* opt_discard */
		ret = btrfs_error_discard_extent(root, start, end + 1 - start);
		if (btrfs_test_opt(root, DISCARD))
			ret = btrfs_error_discard_extent(root, start,
							 end + 1 - start,
							 NULL);


		clear_extent_dirty(unpin, start, end, GFP_NOFS);
		clear_extent_dirty(unpin, start, end, GFP_NOFS);
		btrfs_error_unpin_extent_range(root, start, end);
		btrfs_error_unpin_extent_range(root, start, end);
+26 −17
Original line number Original line Diff line number Diff line
@@ -1738,39 +1738,45 @@ static int remove_extent_backref(struct btrfs_trans_handle *trans,
	return ret;
	return ret;
}
}


static void btrfs_issue_discard(struct block_device *bdev,
static int btrfs_issue_discard(struct block_device *bdev,
				u64 start, u64 len)
				u64 start, u64 len)
{
{
	blkdev_issue_discard(bdev, start >> 9, len >> 9, GFP_NOFS, 0);
	return blkdev_issue_discard(bdev, start >> 9, len >> 9, GFP_NOFS, 0);
}
}


static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
				u64 num_bytes)
				u64 num_bytes, u64 *actual_bytes)
{
{
	int ret;
	int ret;
	u64 map_length = num_bytes;
	u64 discarded_bytes = 0;
	struct btrfs_multi_bio *multi = NULL;
	struct btrfs_multi_bio *multi = NULL;


	if (!btrfs_test_opt(root, DISCARD))
		return 0;


	/* Tell the block device(s) that the sectors can be discarded */
	/* Tell the block device(s) that the sectors can be discarded */
	ret = btrfs_map_block(&root->fs_info->mapping_tree, READ,
	ret = btrfs_map_block(&root->fs_info->mapping_tree, REQ_DISCARD,
			      bytenr, &map_length, &multi, 0);
			      bytenr, &num_bytes, &multi, 0);
	if (!ret) {
	if (!ret) {
		struct btrfs_bio_stripe *stripe = multi->stripes;
		struct btrfs_bio_stripe *stripe = multi->stripes;
		int i;
		int i;


		if (map_length > num_bytes)
			map_length = num_bytes;


		for (i = 0; i < multi->num_stripes; i++, stripe++) {
		for (i = 0; i < multi->num_stripes; i++, stripe++) {
			btrfs_issue_discard(stripe->dev->bdev,
			ret = btrfs_issue_discard(stripe->dev->bdev,
						  stripe->physical,
						  stripe->physical,
					    map_length);
						  stripe->length);
			if (!ret)
				discarded_bytes += stripe->length;
			else if (ret != -EOPNOTSUPP)
				break;
		}
		}
		kfree(multi);
		kfree(multi);
	}
	}
	if (discarded_bytes && ret == -EOPNOTSUPP)
		ret = 0;

	if (actual_bytes)
		*actual_bytes = discarded_bytes;



	return ret;
	return ret;
}
}
@@ -4371,7 +4377,9 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
		if (ret)
		if (ret)
			break;
			break;


		ret = btrfs_discard_extent(root, start, end + 1 - start);
		if (btrfs_test_opt(root, DISCARD))
			ret = btrfs_discard_extent(root, start,
						   end + 1 - start, NULL);


		clear_extent_dirty(unpin, start, end, GFP_NOFS);
		clear_extent_dirty(unpin, start, end, GFP_NOFS);
		unpin_extent_range(root, start, end);
		unpin_extent_range(root, start, end);
@@ -5427,7 +5435,8 @@ int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len)
		return -ENOSPC;
		return -ENOSPC;
	}
	}


	ret = btrfs_discard_extent(root, start, len);
	if (btrfs_test_opt(root, DISCARD))
		ret = btrfs_discard_extent(root, start, len, NULL);


	btrfs_add_free_space(cache, start, len);
	btrfs_add_free_space(cache, start, len);
	btrfs_update_reserved_bytes(cache, len, 0, 1);
	btrfs_update_reserved_bytes(cache, len, 0, 1);
@@ -8765,7 +8774,7 @@ int btrfs_error_unpin_extent_range(struct btrfs_root *root, u64 start, u64 end)
}
}


int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr,
int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr,
			       u64 num_bytes)
			       u64 num_bytes, u64 *actual_bytes)
{
{
	return btrfs_discard_extent(root, bytenr, num_bytes);
	return btrfs_discard_extent(root, bytenr, num_bytes, actual_bytes);
}
}