@@ -724,6 +724,15 @@ static int __open_metadata(struct dm_pool_metadata *pmd)
724724 goto bad_cleanup_data_sm ;
725725 }
726726
727+ /*
728+ * For pool metadata opening process, root setting is redundant
729+ * because it will be set again in __begin_transaction(). But dm
730+ * pool aborting process really needs to get last transaction's
731+ * root to avoid accessing broken btree.
732+ */
733+ pmd -> root = le64_to_cpu (disk_super -> data_mapping_root );
734+ pmd -> details_root = le64_to_cpu (disk_super -> device_details_root );
735+
727736 __setup_btree_details (pmd );
728737 dm_bm_unlock (sblock );
729738
@@ -776,13 +785,15 @@ static int __create_persistent_data_objects(struct dm_pool_metadata *pmd, bool f
776785 return r ;
777786}
778787
779- static void __destroy_persistent_data_objects (struct dm_pool_metadata * pmd )
788+ static void __destroy_persistent_data_objects (struct dm_pool_metadata * pmd ,
789+ bool destroy_bm )
780790{
781791 dm_sm_destroy (pmd -> data_sm );
782792 dm_sm_destroy (pmd -> metadata_sm );
783793 dm_tm_destroy (pmd -> nb_tm );
784794 dm_tm_destroy (pmd -> tm );
785- dm_block_manager_destroy (pmd -> bm );
795+ if (destroy_bm )
796+ dm_block_manager_destroy (pmd -> bm );
786797}
787798
788799static int __begin_transaction (struct dm_pool_metadata * pmd )
@@ -989,7 +1000,7 @@ int dm_pool_metadata_close(struct dm_pool_metadata *pmd)
9891000 }
9901001 pmd_write_unlock (pmd );
9911002 if (!pmd -> fail_io )
992- __destroy_persistent_data_objects (pmd );
1003+ __destroy_persistent_data_objects (pmd , true );
9931004
9941005 kfree (pmd );
9951006 return 0 ;
@@ -1860,19 +1871,52 @@ static void __set_abort_with_changes_flags(struct dm_pool_metadata *pmd)
18601871int dm_pool_abort_metadata (struct dm_pool_metadata * pmd )
18611872{
18621873 int r = - EINVAL ;
1874+ struct dm_block_manager * old_bm = NULL , * new_bm = NULL ;
1875+
1876+ /* fail_io is double-checked with pmd->root_lock held below */
1877+ if (unlikely (pmd -> fail_io ))
1878+ return r ;
1879+
1880+ /*
1881+ * Replacement block manager (new_bm) is created and old_bm destroyed outside of
1882+ * pmd root_lock to avoid ABBA deadlock that would result (due to life-cycle of
1883+ * shrinker associated with the block manager's bufio client vs pmd root_lock).
1884+ * - must take shrinker_rwsem without holding pmd->root_lock
1885+ */
1886+ new_bm = dm_block_manager_create (pmd -> bdev , THIN_METADATA_BLOCK_SIZE << SECTOR_SHIFT ,
1887+ THIN_MAX_CONCURRENT_LOCKS );
18631888
18641889 pmd_write_lock (pmd );
1865- if (pmd -> fail_io )
1890+ if (pmd -> fail_io ) {
1891+ pmd_write_unlock (pmd );
18661892 goto out ;
1893+ }
18671894
18681895 __set_abort_with_changes_flags (pmd );
1869- __destroy_persistent_data_objects (pmd );
1870- r = __create_persistent_data_objects (pmd , false);
1896+ __destroy_persistent_data_objects (pmd , false);
1897+ old_bm = pmd -> bm ;
1898+ if (IS_ERR (new_bm )) {
1899+ DMERR ("could not create block manager during abort" );
1900+ pmd -> bm = NULL ;
1901+ r = PTR_ERR (new_bm );
1902+ goto out_unlock ;
1903+ }
1904+
1905+ pmd -> bm = new_bm ;
1906+ r = __open_or_format_metadata (pmd , false);
1907+ if (r ) {
1908+ pmd -> bm = NULL ;
1909+ goto out_unlock ;
1910+ }
1911+ new_bm = NULL ;
1912+ out_unlock :
18711913 if (r )
18721914 pmd -> fail_io = true;
1873-
1874- out :
18751915 pmd_write_unlock (pmd );
1916+ dm_block_manager_destroy (old_bm );
1917+ out :
1918+ if (new_bm && !IS_ERR (new_bm ))
1919+ dm_block_manager_destroy (new_bm );
18761920
18771921 return r ;
18781922}
0 commit comments