Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Josef Bacik and committed by
Chris Mason
d5e2003c 2ab1ba68

+29 -2
+10 -2
fs/btrfs/extent-tree.c
··· 1782 1782 1783 1783 1784 1784 for (i = 0; i < multi->num_stripes; i++, stripe++) { 1785 + if (!stripe->dev->can_discard) 1786 + continue; 1787 + 1785 1788 ret = btrfs_issue_discard(stripe->dev->bdev, 1786 1789 stripe->physical, 1787 1790 stripe->length); ··· 1792 1789 discarded_bytes += stripe->length; 1793 1790 else if (ret != -EOPNOTSUPP) 1794 1791 break; 1792 + 1793 + /* 1794 + * Just in case we get back EOPNOTSUPP for some reason, 1795 + * just ignore the return value so we don't screw up 1796 + * people calling discard_extent. 1797 + */ 1798 + ret = 0; 1795 1799 } 1796 1800 kfree(multi); 1797 1801 } 1798 - if (discarded_bytes && ret == -EOPNOTSUPP) 1799 - ret = 0; 1800 1802 1801 1803 if (actual_bytes) 1802 1804 *actual_bytes = discarded_bytes;
+17
fs/btrfs/volumes.c
··· 517 517 fs_devices->rw_devices--; 518 518 } 519 519 520 + if (device->can_discard) 521 + fs_devices->num_can_discard--; 522 + 520 523 new_device = kmalloc(sizeof(*new_device), GFP_NOFS); 521 524 BUG_ON(!new_device); 522 525 memcpy(new_device, device, sizeof(*new_device)); ··· 528 525 new_device->bdev = NULL; 529 526 new_device->writeable = 0; 530 527 new_device->in_fs_metadata = 0; 528 + new_device->can_discard = 0; 531 529 list_replace_rcu(&device->dev_list, &new_device->dev_list); 532 530 533 531 call_rcu(&device->rcu, free_device); ··· 568 564 static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices, 569 565 fmode_t flags, void *holder) 570 566 { 567 + struct request_queue *q; 571 568 struct block_device *bdev; 572 569 struct list_head *head = &fs_devices->devices; 573 570 struct btrfs_device *device; ··· 623 618 } else { 624 619 device->writeable = !bdev_read_only(bdev); 625 620 seeding = 0; 621 + } 622 + 623 + q = bdev_get_queue(bdev); 624 + if (blk_queue_discard(q)) { 625 + device->can_discard = 1; 626 + fs_devices->num_can_discard++; 626 627 } 627 628 628 629 device->bdev = bdev; ··· 1571 1560 1572 1561 int btrfs_init_new_device(struct btrfs_root *root, char *device_path) 1573 1562 { 1563 + struct request_queue *q; 1574 1564 struct btrfs_trans_handle *trans; 1575 1565 struct btrfs_device *device; 1576 1566 struct block_device *bdev; ··· 1641 1629 1642 1630 lock_chunks(root); 1643 1631 1632 + q = bdev_get_queue(bdev); 1633 + if (blk_queue_discard(q)) 1634 + device->can_discard = 1; 1644 1635 device->writeable = 1; 1645 1636 device->work.func = pending_bios_fn; 1646 1637 generate_random_uuid(device->uuid); ··· 1679 1664 root->fs_info->fs_devices->num_devices++; 1680 1665 root->fs_info->fs_devices->open_devices++; 1681 1666 root->fs_info->fs_devices->rw_devices++; 1667 + if (device->can_discard) 1668 + root->fs_info->fs_devices->num_can_discard++; 1682 1669 root->fs_info->fs_devices->total_rw_bytes += device->total_bytes; 1683 1670 1684 1671 if (!blk_queue_nonrot(bdev_get_queue(bdev)))
+2
fs/btrfs/volumes.h
··· 48 48 int writeable; 49 49 int in_fs_metadata; 50 50 int missing; 51 + int can_discard; 51 52 52 53 spinlock_t io_lock; 53 54 ··· 105 104 u64 rw_devices; 106 105 u64 missing_devices; 107 106 u64 total_rw_bytes; 107 + u64 num_can_discard; 108 108 struct block_device *latest_bdev; 109 109 110 110 /* all of the devices in the FS, protected by a mutex