Btrfs: detect wether a device supports discard
We have a problem where if a user specifies discard but doesn't actually support it we will return EOPNOTSUPP from btrfs_discard_extent. This is a problem because this gets called (in a fashion) from the tree log recovery code, which has a nice little BUG_ON(ret) after it, which causes us to fail the tree log replay. So instead detect wether our devices support discard when we're adding them and then don't issue discards if we know that the device doesn't support it. And just for good measure set ret = 0 in btrfs_issue_discard just in case we still get EOPNOTSUPP so we don't screw anybody up like this again. Thanks, Signed-off-by: Josef Bacik <josef@redhat.com> Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
@@ -517,6 +517,9 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
|
||||
fs_devices->rw_devices--;
|
||||
}
|
||||
|
||||
if (device->can_discard)
|
||||
fs_devices->num_can_discard--;
|
||||
|
||||
new_device = kmalloc(sizeof(*new_device), GFP_NOFS);
|
||||
BUG_ON(!new_device);
|
||||
memcpy(new_device, device, sizeof(*new_device));
|
||||
@@ -525,6 +528,7 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
|
||||
new_device->bdev = NULL;
|
||||
new_device->writeable = 0;
|
||||
new_device->in_fs_metadata = 0;
|
||||
new_device->can_discard = 0;
|
||||
list_replace_rcu(&device->dev_list, &new_device->dev_list);
|
||||
|
||||
call_rcu(&device->rcu, free_device);
|
||||
@@ -564,6 +568,7 @@ int btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
|
||||
static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
|
||||
fmode_t flags, void *holder)
|
||||
{
|
||||
struct request_queue *q;
|
||||
struct block_device *bdev;
|
||||
struct list_head *head = &fs_devices->devices;
|
||||
struct btrfs_device *device;
|
||||
@@ -620,6 +625,12 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
|
||||
seeding = 0;
|
||||
}
|
||||
|
||||
q = bdev_get_queue(bdev);
|
||||
if (blk_queue_discard(q)) {
|
||||
device->can_discard = 1;
|
||||
fs_devices->num_can_discard++;
|
||||
}
|
||||
|
||||
device->bdev = bdev;
|
||||
device->in_fs_metadata = 0;
|
||||
device->mode = flags;
|
||||
@@ -1560,6 +1571,7 @@ error:
|
||||
|
||||
int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
|
||||
{
|
||||
struct request_queue *q;
|
||||
struct btrfs_trans_handle *trans;
|
||||
struct btrfs_device *device;
|
||||
struct block_device *bdev;
|
||||
@@ -1629,6 +1641,9 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
|
||||
|
||||
lock_chunks(root);
|
||||
|
||||
q = bdev_get_queue(bdev);
|
||||
if (blk_queue_discard(q))
|
||||
device->can_discard = 1;
|
||||
device->writeable = 1;
|
||||
device->work.func = pending_bios_fn;
|
||||
generate_random_uuid(device->uuid);
|
||||
@@ -1664,6 +1679,8 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
|
||||
root->fs_info->fs_devices->num_devices++;
|
||||
root->fs_info->fs_devices->open_devices++;
|
||||
root->fs_info->fs_devices->rw_devices++;
|
||||
if (device->can_discard)
|
||||
root->fs_info->fs_devices->num_can_discard++;
|
||||
root->fs_info->fs_devices->total_rw_bytes += device->total_bytes;
|
||||
|
||||
if (!blk_queue_nonrot(bdev_get_queue(bdev)))
|
||||
|
Reference in New Issue
Block a user