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: Li Dongyang <lidongyang@novell.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
Li Dongyang 2011-03-24 10:24:27 +00:00 committed by root
parent fce3bb9a1b
commit 5378e60734
3 changed files with 31 additions and 19 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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);
} }