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

Configure Feed

Select the types of activity you want to include in your feed.

dm cache: Fix ABBA deadlock between shrink_slab and dm_cache_metadata_abort

Same ABBA deadlock pattern fixed in commit 4b60f452ec51 ("dm thin: Fix
ABBA deadlock between shrink_slab and dm_pool_abort_metadata") to
DM-cache's metadata.

Reported-by: Zhihao Cheng <chengzhihao1@huawei.com>
Cc: stable@vger.kernel.org
Fixes: 028ae9f76f29 ("dm cache: add fail io mode and needs_check flag")
Signed-off-by: Mike Snitzer <snitzer@kernel.org>

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