aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJosef Bacik <josef@redhat.com>2011-08-04 10:52:27 -0400
committerChris Mason <chris.mason@oracle.com>2011-08-16 21:09:15 -0400
commitd5e2003c2bcda93a8f2e668eb4642d70c9c38301 (patch)
tree336234b9d9a144f180bc51738f55fef7f743b725 /fs
parent2ab1ba68aeaecd41c4b34f0eaf1d70a37367fb1a (diff)
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>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/extent-tree.c12
-rw-r--r--fs/btrfs/volumes.c17
-rw-r--r--fs/btrfs/volumes.h2
3 files changed, 29 insertions, 2 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 66bac226944e..059dfa048cc0 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -1782,6 +1782,9 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
1782 1782
1783 1783
1784 for (i = 0; i < multi->num_stripes; i++, stripe++) { 1784 for (i = 0; i < multi->num_stripes; i++, stripe++) {
1785 if (!stripe->dev->can_discard)
1786 continue;
1787
1785 ret = btrfs_issue_discard(stripe->dev->bdev, 1788 ret = btrfs_issue_discard(stripe->dev->bdev,
1786 stripe->physical, 1789 stripe->physical,
1787 stripe->length); 1790 stripe->length);
@@ -1789,11 +1792,16 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
1789 discarded_bytes += stripe->length; 1792 discarded_bytes += stripe->length;
1790 else if (ret != -EOPNOTSUPP) 1793 else if (ret != -EOPNOTSUPP)
1791 break; 1794 break;
1795
1796 /*
1797 * Just in case we get back EOPNOTSUPP for some reason,
1798 * just ignore the return value so we don't screw up
1799 * people calling discard_extent.
1800 */
1801 ret = 0;
1792 } 1802 }
1793 kfree(multi); 1803 kfree(multi);
1794 } 1804 }
1795 if (discarded_bytes && ret == -EOPNOTSUPP)
1796 ret = 0;
1797 1805
1798 if (actual_bytes) 1806 if (actual_bytes)
1799 *actual_bytes = discarded_bytes; 1807 *actual_bytes = discarded_bytes;
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 3c5f2fcd82c1..a595f8775c37 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -517,6 +517,9 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
517 fs_devices->rw_devices--; 517 fs_devices->rw_devices--;
518 } 518 }
519 519
520 if (device->can_discard)
521 fs_devices->num_can_discard--;
522
520 new_device = kmalloc(sizeof(*new_device), GFP_NOFS); 523 new_device = kmalloc(sizeof(*new_device), GFP_NOFS);
521 BUG_ON(!new_device); 524 BUG_ON(!new_device);
522 memcpy(new_device, device, sizeof(*new_device)); 525 memcpy(new_device, device, sizeof(*new_device));
@@ -525,6 +528,7 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
525 new_device->bdev = NULL; 528 new_device->bdev = NULL;
526 new_device->writeable = 0; 529 new_device->writeable = 0;
527 new_device->in_fs_metadata = 0; 530 new_device->in_fs_metadata = 0;
531 new_device->can_discard = 0;
528 list_replace_rcu(&device->dev_list, &new_device->dev_list); 532 list_replace_rcu(&device->dev_list, &new_device->dev_list);
529 533
530 call_rcu(&device->rcu, free_device); 534 call_rcu(&device->rcu, free_device);
@@ -564,6 +568,7 @@ int btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
564static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices, 568static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
565 fmode_t flags, void *holder) 569 fmode_t flags, void *holder)
566{ 570{
571 struct request_queue *q;
567 struct block_device *bdev; 572 struct block_device *bdev;
568 struct list_head *head = &fs_devices->devices; 573 struct list_head *head = &fs_devices->devices;
569 struct btrfs_device *device; 574 struct btrfs_device *device;
@@ -620,6 +625,12 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
620 seeding = 0; 625 seeding = 0;
621 } 626 }
622 627
628 q = bdev_get_queue(bdev);
629 if (blk_queue_discard(q)) {
630 device->can_discard = 1;
631 fs_devices->num_can_discard++;
632 }
633
623 device->bdev = bdev; 634 device->bdev = bdev;
624 device->in_fs_metadata = 0; 635 device->in_fs_metadata = 0;
625 device->mode = flags; 636 device->mode = flags;
@@ -1560,6 +1571,7 @@ error:
1560 1571
1561int btrfs_init_new_device(struct btrfs_root *root, char *device_path) 1572int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
1562{ 1573{
1574 struct request_queue *q;
1563 struct btrfs_trans_handle *trans; 1575 struct btrfs_trans_handle *trans;
1564 struct btrfs_device *device; 1576 struct btrfs_device *device;
1565 struct block_device *bdev; 1577 struct block_device *bdev;
@@ -1629,6 +1641,9 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
1629 1641
1630 lock_chunks(root); 1642 lock_chunks(root);
1631 1643
1644 q = bdev_get_queue(bdev);
1645 if (blk_queue_discard(q))
1646 device->can_discard = 1;
1632 device->writeable = 1; 1647 device->writeable = 1;
1633 device->work.func = pending_bios_fn; 1648 device->work.func = pending_bios_fn;
1634 generate_random_uuid(device->uuid); 1649 generate_random_uuid(device->uuid);
@@ -1664,6 +1679,8 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
1664 root->fs_info->fs_devices->num_devices++; 1679 root->fs_info->fs_devices->num_devices++;
1665 root->fs_info->fs_devices->open_devices++; 1680 root->fs_info->fs_devices->open_devices++;
1666 root->fs_info->fs_devices->rw_devices++; 1681 root->fs_info->fs_devices->rw_devices++;
1682 if (device->can_discard)
1683 root->fs_info->fs_devices->num_can_discard++;
1667 root->fs_info->fs_devices->total_rw_bytes += device->total_bytes; 1684 root->fs_info->fs_devices->total_rw_bytes += device->total_bytes;
1668 1685
1669 if (!blk_queue_nonrot(bdev_get_queue(bdev))) 1686 if (!blk_queue_nonrot(bdev_get_queue(bdev)))
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 7c12d61ae7ae..6d866db4e177 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -48,6 +48,7 @@ struct btrfs_device {
48 int writeable; 48 int writeable;
49 int in_fs_metadata; 49 int in_fs_metadata;
50 int missing; 50 int missing;
51 int can_discard;
51 52
52 spinlock_t io_lock; 53 spinlock_t io_lock;
53 54
@@ -104,6 +105,7 @@ struct btrfs_fs_devices {
104 u64 rw_devices; 105 u64 rw_devices;
105 u64 missing_devices; 106 u64 missing_devices;
106 u64 total_rw_bytes; 107 u64 total_rw_bytes;
108 u64 num_can_discard;
107 struct block_device *latest_bdev; 109 struct block_device *latest_bdev;
108 110
109 /* all of the devices in the FS, protected by a mutex 111 /* all of the devices in the FS, protected by a mutex