Skip to content

Commit

Permalink
Btrfs: detect wether a device supports discard
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Josef Bacik authored and Chris Mason committed Aug 17, 2011
1 parent 2ab1ba6 commit d5e2003
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 2 deletions.
12 changes: 10 additions & 2 deletions fs/btrfs/extent-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -1782,18 +1782,26 @@ 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);
if (!ret)
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;
Expand Down
17 changes: 17 additions & 0 deletions fs/btrfs/volumes.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1560,6 +1571,7 @@ static int btrfs_finish_sprout(struct btrfs_trans_handle *trans,

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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)))
Expand Down
2 changes: 2 additions & 0 deletions fs/btrfs/volumes.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ struct btrfs_device {
int writeable;
int in_fs_metadata;
int missing;
int can_discard;

spinlock_t io_lock;

Expand Down Expand Up @@ -104,6 +105,7 @@ struct btrfs_fs_devices {
u64 rw_devices;
u64 missing_devices;
u64 total_rw_bytes;
u64 num_can_discard;
struct block_device *latest_bdev;

/* all of the devices in the FS, protected by a mutex
Expand Down

0 comments on commit d5e2003

Please sign in to comment.