hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/md/dm-thin-metadata.c
....@@ -701,6 +701,15 @@
701701 goto bad_cleanup_data_sm;
702702 }
703703
704
+ /*
705
+ * For pool metadata opening process, root setting is redundant
706
+ * because it will be set again in __begin_transaction(). But dm
707
+ * pool aborting process really needs to get last transaction's
708
+ * root to avoid accessing broken btree.
709
+ */
710
+ pmd->root = le64_to_cpu(disk_super->data_mapping_root);
711
+ pmd->details_root = le64_to_cpu(disk_super->device_details_root);
712
+
704713 __setup_btree_details(pmd);
705714 dm_bm_unlock(sblock);
706715
....@@ -753,13 +762,15 @@
753762 return r;
754763 }
755764
756
-static void __destroy_persistent_data_objects(struct dm_pool_metadata *pmd)
765
+static void __destroy_persistent_data_objects(struct dm_pool_metadata *pmd,
766
+ bool destroy_bm)
757767 {
758768 dm_sm_destroy(pmd->data_sm);
759769 dm_sm_destroy(pmd->metadata_sm);
760770 dm_tm_destroy(pmd->nb_tm);
761771 dm_tm_destroy(pmd->tm);
762
- dm_block_manager_destroy(pmd->bm);
772
+ if (destroy_bm)
773
+ dm_block_manager_destroy(pmd->bm);
763774 }
764775
765776 static int __begin_transaction(struct dm_pool_metadata *pmd)
....@@ -966,7 +977,7 @@
966977 }
967978 pmd_write_unlock(pmd);
968979 if (!pmd->fail_io)
969
- __destroy_persistent_data_objects(pmd);
980
+ __destroy_persistent_data_objects(pmd, true);
970981
971982 kfree(pmd);
972983 return 0;
....@@ -1873,19 +1884,52 @@
18731884 int dm_pool_abort_metadata(struct dm_pool_metadata *pmd)
18741885 {
18751886 int r = -EINVAL;
1887
+ struct dm_block_manager *old_bm = NULL, *new_bm = NULL;
1888
+
1889
+ /* fail_io is double-checked with pmd->root_lock held below */
1890
+ if (unlikely(pmd->fail_io))
1891
+ return r;
1892
+
1893
+ /*
1894
+ * Replacement block manager (new_bm) is created and old_bm destroyed outside of
1895
+ * pmd root_lock to avoid ABBA deadlock that would result (due to life-cycle of
1896
+ * shrinker associated with the block manager's bufio client vs pmd root_lock).
1897
+ * - must take shrinker_rwsem without holding pmd->root_lock
1898
+ */
1899
+ new_bm = dm_block_manager_create(pmd->bdev, THIN_METADATA_BLOCK_SIZE << SECTOR_SHIFT,
1900
+ THIN_MAX_CONCURRENT_LOCKS);
18761901
18771902 pmd_write_lock(pmd);
1878
- if (pmd->fail_io)
1903
+ if (pmd->fail_io) {
1904
+ pmd_write_unlock(pmd);
18791905 goto out;
1906
+ }
18801907
18811908 __set_abort_with_changes_flags(pmd);
1882
- __destroy_persistent_data_objects(pmd);
1883
- r = __create_persistent_data_objects(pmd, false);
1909
+ __destroy_persistent_data_objects(pmd, false);
1910
+ old_bm = pmd->bm;
1911
+ if (IS_ERR(new_bm)) {
1912
+ DMERR("could not create block manager during abort");
1913
+ pmd->bm = NULL;
1914
+ r = PTR_ERR(new_bm);
1915
+ goto out_unlock;
1916
+ }
1917
+
1918
+ pmd->bm = new_bm;
1919
+ r = __open_or_format_metadata(pmd, false);
1920
+ if (r) {
1921
+ pmd->bm = NULL;
1922
+ goto out_unlock;
1923
+ }
1924
+ new_bm = NULL;
1925
+out_unlock:
18841926 if (r)
18851927 pmd->fail_io = true;
1886
-
1887
-out:
18881928 pmd_write_unlock(pmd);
1929
+ dm_block_manager_destroy(old_bm);
1930
+out:
1931
+ if (new_bm && !IS_ERR(new_bm))
1932
+ dm_block_manager_destroy(new_bm);
18891933
18901934 return r;
18911935 }