|
@@ -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,
|
|
|
|
- bytenr, &map_length, &multi, 0);
|
|
|
|
|
|
+ ret = btrfs_map_block(&root->fs_info->mapping_tree, REQ_DISCARD,
|
|
|
|
+ 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,
|
|
|
|
- stripe->physical,
|
|
|
|
- map_length);
|
|
|
|
|
|
+ ret = btrfs_issue_discard(stripe->dev->bdev,
|
|
|
|
+ stripe->physical,
|
|
|
|
+ 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);
|
|
}
|
|
}
|