.. | .. |
---|
551 | 551 | return r; |
---|
552 | 552 | } |
---|
553 | 553 | |
---|
554 | | -static void __destroy_persistent_data_objects(struct dm_cache_metadata *cmd) |
---|
| 554 | +static void __destroy_persistent_data_objects(struct dm_cache_metadata *cmd, |
---|
| 555 | + bool destroy_bm) |
---|
555 | 556 | { |
---|
556 | 557 | dm_sm_destroy(cmd->metadata_sm); |
---|
557 | 558 | dm_tm_destroy(cmd->tm); |
---|
558 | | - dm_block_manager_destroy(cmd->bm); |
---|
| 559 | + if (destroy_bm) |
---|
| 560 | + dm_block_manager_destroy(cmd->bm); |
---|
559 | 561 | } |
---|
560 | 562 | |
---|
561 | 563 | typedef unsigned long (*flags_mutator)(unsigned long); |
---|
.. | .. |
---|
826 | 828 | cmd2 = lookup(bdev); |
---|
827 | 829 | if (cmd2) { |
---|
828 | 830 | mutex_unlock(&table_lock); |
---|
829 | | - __destroy_persistent_data_objects(cmd); |
---|
| 831 | + __destroy_persistent_data_objects(cmd, true); |
---|
830 | 832 | kfree(cmd); |
---|
831 | 833 | return cmd2; |
---|
832 | 834 | } |
---|
.. | .. |
---|
874 | 876 | mutex_unlock(&table_lock); |
---|
875 | 877 | |
---|
876 | 878 | if (!cmd->fail_io) |
---|
877 | | - __destroy_persistent_data_objects(cmd); |
---|
| 879 | + __destroy_persistent_data_objects(cmd, true); |
---|
878 | 880 | kfree(cmd); |
---|
879 | 881 | } |
---|
880 | 882 | } |
---|
.. | .. |
---|
1808 | 1810 | |
---|
1809 | 1811 | int dm_cache_metadata_abort(struct dm_cache_metadata *cmd) |
---|
1810 | 1812 | { |
---|
1811 | | - int r; |
---|
| 1813 | + int r = -EINVAL; |
---|
| 1814 | + struct dm_block_manager *old_bm = NULL, *new_bm = NULL; |
---|
| 1815 | + |
---|
| 1816 | + /* fail_io is double-checked with cmd->root_lock held below */ |
---|
| 1817 | + if (unlikely(cmd->fail_io)) |
---|
| 1818 | + return r; |
---|
| 1819 | + |
---|
| 1820 | + /* |
---|
| 1821 | + * Replacement block manager (new_bm) is created and old_bm destroyed outside of |
---|
| 1822 | + * cmd root_lock to avoid ABBA deadlock that would result (due to life-cycle of |
---|
| 1823 | + * shrinker associated with the block manager's bufio client vs cmd root_lock). |
---|
| 1824 | + * - must take shrinker_rwsem without holding cmd->root_lock |
---|
| 1825 | + */ |
---|
| 1826 | + new_bm = dm_block_manager_create(cmd->bdev, DM_CACHE_METADATA_BLOCK_SIZE << SECTOR_SHIFT, |
---|
| 1827 | + CACHE_MAX_CONCURRENT_LOCKS); |
---|
1812 | 1828 | |
---|
1813 | 1829 | WRITE_LOCK(cmd); |
---|
1814 | | - __destroy_persistent_data_objects(cmd); |
---|
1815 | | - r = __create_persistent_data_objects(cmd, false); |
---|
| 1830 | + if (cmd->fail_io) { |
---|
| 1831 | + WRITE_UNLOCK(cmd); |
---|
| 1832 | + goto out; |
---|
| 1833 | + } |
---|
| 1834 | + |
---|
| 1835 | + __destroy_persistent_data_objects(cmd, false); |
---|
| 1836 | + old_bm = cmd->bm; |
---|
| 1837 | + if (IS_ERR(new_bm)) { |
---|
| 1838 | + DMERR("could not create block manager during abort"); |
---|
| 1839 | + cmd->bm = NULL; |
---|
| 1840 | + r = PTR_ERR(new_bm); |
---|
| 1841 | + goto out_unlock; |
---|
| 1842 | + } |
---|
| 1843 | + |
---|
| 1844 | + cmd->bm = new_bm; |
---|
| 1845 | + r = __open_or_format_metadata(cmd, false); |
---|
| 1846 | + if (r) { |
---|
| 1847 | + cmd->bm = NULL; |
---|
| 1848 | + goto out_unlock; |
---|
| 1849 | + } |
---|
| 1850 | + new_bm = NULL; |
---|
| 1851 | +out_unlock: |
---|
1816 | 1852 | if (r) |
---|
1817 | 1853 | cmd->fail_io = true; |
---|
1818 | 1854 | WRITE_UNLOCK(cmd); |
---|
| 1855 | + dm_block_manager_destroy(old_bm); |
---|
| 1856 | +out: |
---|
| 1857 | + if (new_bm && !IS_ERR(new_bm)) |
---|
| 1858 | + dm_block_manager_destroy(new_bm); |
---|
1819 | 1859 | |
---|
1820 | 1860 | return r; |
---|
1821 | 1861 | } |
---|