diff options
| -rw-r--r-- | drivers/md/dm-cache-metadata.c | 101 | ||||
| -rw-r--r-- | drivers/md/dm-cache-target.c | 89 | ||||
| -rw-r--r-- | drivers/md/dm.c | 9 |
3 files changed, 152 insertions, 47 deletions
diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c index 9fc616c2755e..21b156242e42 100644 --- a/drivers/md/dm-cache-metadata.c +++ b/drivers/md/dm-cache-metadata.c | |||
| @@ -94,6 +94,9 @@ struct cache_disk_superblock { | |||
| 94 | } __packed; | 94 | } __packed; |
| 95 | 95 | ||
| 96 | struct dm_cache_metadata { | 96 | struct dm_cache_metadata { |
| 97 | atomic_t ref_count; | ||
| 98 | struct list_head list; | ||
| 99 | |||
| 97 | struct block_device *bdev; | 100 | struct block_device *bdev; |
| 98 | struct dm_block_manager *bm; | 101 | struct dm_block_manager *bm; |
| 99 | struct dm_space_map *metadata_sm; | 102 | struct dm_space_map *metadata_sm; |
| @@ -669,10 +672,10 @@ static void unpack_value(__le64 value_le, dm_oblock_t *block, unsigned *flags) | |||
| 669 | 672 | ||
| 670 | /*----------------------------------------------------------------*/ | 673 | /*----------------------------------------------------------------*/ |
| 671 | 674 | ||
| 672 | struct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev, | 675 | static struct dm_cache_metadata *metadata_open(struct block_device *bdev, |
| 673 | sector_t data_block_size, | 676 | sector_t data_block_size, |
| 674 | bool may_format_device, | 677 | bool may_format_device, |
| 675 | size_t policy_hint_size) | 678 | size_t policy_hint_size) |
| 676 | { | 679 | { |
| 677 | int r; | 680 | int r; |
| 678 | struct dm_cache_metadata *cmd; | 681 | struct dm_cache_metadata *cmd; |
| @@ -683,6 +686,7 @@ struct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev, | |||
| 683 | return NULL; | 686 | return NULL; |
| 684 | } | 687 | } |
| 685 | 688 | ||
| 689 | atomic_set(&cmd->ref_count, 1); | ||
| 686 | init_rwsem(&cmd->root_lock); | 690 | init_rwsem(&cmd->root_lock); |
| 687 | cmd->bdev = bdev; | 691 | cmd->bdev = bdev; |
| 688 | cmd->data_block_size = data_block_size; | 692 | cmd->data_block_size = data_block_size; |
| @@ -705,10 +709,95 @@ struct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev, | |||
| 705 | return cmd; | 709 | return cmd; |
| 706 | } | 710 | } |
| 707 | 711 | ||
| 712 | /* | ||
| 713 | * We keep a little list of ref counted metadata objects to prevent two | ||
| 714 | * different target instances creating separate bufio instances. This is | ||
| 715 | * an issue if a table is reloaded before the suspend. | ||
| 716 | */ | ||
| 717 | static DEFINE_MUTEX(table_lock); | ||
| 718 | static LIST_HEAD(table); | ||
| 719 | |||
| 720 | static struct dm_cache_metadata *lookup(struct block_device *bdev) | ||
| 721 | { | ||
| 722 | struct dm_cache_metadata *cmd; | ||
| 723 | |||
| 724 | list_for_each_entry(cmd, &table, list) | ||
| 725 | if (cmd->bdev == bdev) { | ||
| 726 | atomic_inc(&cmd->ref_count); | ||
| 727 | return cmd; | ||
| 728 | } | ||
| 729 | |||
| 730 | return NULL; | ||
| 731 | } | ||
| 732 | |||
| 733 | static struct dm_cache_metadata *lookup_or_open(struct block_device *bdev, | ||
| 734 | sector_t data_block_size, | ||
| 735 | bool may_format_device, | ||
| 736 | size_t policy_hint_size) | ||
| 737 | { | ||
| 738 | struct dm_cache_metadata *cmd, *cmd2; | ||
| 739 | |||
| 740 | mutex_lock(&table_lock); | ||
| 741 | cmd = lookup(bdev); | ||
| 742 | mutex_unlock(&table_lock); | ||
| 743 | |||
| 744 | if (cmd) | ||
| 745 | return cmd; | ||
| 746 | |||
| 747 | cmd = metadata_open(bdev, data_block_size, may_format_device, policy_hint_size); | ||
| 748 | if (cmd) { | ||
| 749 | mutex_lock(&table_lock); | ||
| 750 | cmd2 = lookup(bdev); | ||
| 751 | if (cmd2) { | ||
| 752 | mutex_unlock(&table_lock); | ||
| 753 | __destroy_persistent_data_objects(cmd); | ||
| 754 | kfree(cmd); | ||
| 755 | return cmd2; | ||
| 756 | } | ||
| 757 | list_add(&cmd->list, &table); | ||
| 758 | mutex_unlock(&table_lock); | ||
| 759 | } | ||
| 760 | |||
| 761 | return cmd; | ||
| 762 | } | ||
| 763 | |||
| 764 | static bool same_params(struct dm_cache_metadata *cmd, sector_t data_block_size) | ||
| 765 | { | ||
| 766 | if (cmd->data_block_size != data_block_size) { | ||
| 767 | DMERR("data_block_size (%llu) different from that in metadata (%llu)\n", | ||
| 768 | (unsigned long long) data_block_size, | ||
| 769 | (unsigned long long) cmd->data_block_size); | ||
| 770 | return false; | ||
| 771 | } | ||
| 772 | |||
| 773 | return true; | ||
| 774 | } | ||
| 775 | |||
| 776 | struct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev, | ||
| 777 | sector_t data_block_size, | ||
| 778 | bool may_format_device, | ||
| 779 | size_t policy_hint_size) | ||
| 780 | { | ||
| 781 | struct dm_cache_metadata *cmd = lookup_or_open(bdev, data_block_size, | ||
| 782 | may_format_device, policy_hint_size); | ||
| 783 | if (cmd && !same_params(cmd, data_block_size)) { | ||
| 784 | dm_cache_metadata_close(cmd); | ||
| 785 | return NULL; | ||
| 786 | } | ||
| 787 | |||
| 788 | return cmd; | ||
| 789 | } | ||
| 790 | |||
| 708 | void dm_cache_metadata_close(struct dm_cache_metadata *cmd) | 791 | void dm_cache_metadata_close(struct dm_cache_metadata *cmd) |
| 709 | { | 792 | { |
| 710 | __destroy_persistent_data_objects(cmd); | 793 | if (atomic_dec_and_test(&cmd->ref_count)) { |
| 711 | kfree(cmd); | 794 | mutex_lock(&table_lock); |
| 795 | list_del(&cmd->list); | ||
| 796 | mutex_unlock(&table_lock); | ||
| 797 | |||
| 798 | __destroy_persistent_data_objects(cmd); | ||
| 799 | kfree(cmd); | ||
| 800 | } | ||
| 712 | } | 801 | } |
| 713 | 802 | ||
| 714 | /* | 803 | /* |
diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index 1e96d7889f51..e1650539cc2f 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c | |||
| @@ -221,7 +221,13 @@ struct cache { | |||
| 221 | struct list_head need_commit_migrations; | 221 | struct list_head need_commit_migrations; |
| 222 | sector_t migration_threshold; | 222 | sector_t migration_threshold; |
| 223 | wait_queue_head_t migration_wait; | 223 | wait_queue_head_t migration_wait; |
| 224 | atomic_t nr_migrations; | 224 | atomic_t nr_allocated_migrations; |
| 225 | |||
| 226 | /* | ||
| 227 | * The number of in flight migrations that are performing | ||
| 228 | * background io. eg, promotion, writeback. | ||
| 229 | */ | ||
| 230 | atomic_t nr_io_migrations; | ||
| 225 | 231 | ||
| 226 | wait_queue_head_t quiescing_wait; | 232 | wait_queue_head_t quiescing_wait; |
| 227 | atomic_t quiescing; | 233 | atomic_t quiescing; |
| @@ -258,7 +264,6 @@ struct cache { | |||
| 258 | struct dm_deferred_set *all_io_ds; | 264 | struct dm_deferred_set *all_io_ds; |
| 259 | 265 | ||
| 260 | mempool_t *migration_pool; | 266 | mempool_t *migration_pool; |
| 261 | struct dm_cache_migration *next_migration; | ||
| 262 | 267 | ||
| 263 | struct dm_cache_policy *policy; | 268 | struct dm_cache_policy *policy; |
| 264 | unsigned policy_nr_args; | 269 | unsigned policy_nr_args; |
| @@ -350,10 +355,31 @@ static void free_prison_cell(struct cache *cache, struct dm_bio_prison_cell *cel | |||
| 350 | dm_bio_prison_free_cell(cache->prison, cell); | 355 | dm_bio_prison_free_cell(cache->prison, cell); |
| 351 | } | 356 | } |
| 352 | 357 | ||
| 358 | static struct dm_cache_migration *alloc_migration(struct cache *cache) | ||
| 359 | { | ||
| 360 | struct dm_cache_migration *mg; | ||
| 361 | |||
| 362 | mg = mempool_alloc(cache->migration_pool, GFP_NOWAIT); | ||
| 363 | if (mg) { | ||
| 364 | mg->cache = cache; | ||
| 365 | atomic_inc(&mg->cache->nr_allocated_migrations); | ||
| 366 | } | ||
| 367 | |||
| 368 | return mg; | ||
| 369 | } | ||
| 370 | |||
| 371 | static void free_migration(struct dm_cache_migration *mg) | ||
| 372 | { | ||
| 373 | if (atomic_dec_and_test(&mg->cache->nr_allocated_migrations)) | ||
| 374 | wake_up(&mg->cache->migration_wait); | ||
| 375 | |||
| 376 | mempool_free(mg, mg->cache->migration_pool); | ||
| 377 | } | ||
| 378 | |||
| 353 | static int prealloc_data_structs(struct cache *cache, struct prealloc *p) | 379 | static int prealloc_data_structs(struct cache *cache, struct prealloc *p) |
| 354 | { | 380 | { |
| 355 | if (!p->mg) { | 381 | if (!p->mg) { |
| 356 | p->mg = mempool_alloc(cache->migration_pool, GFP_NOWAIT); | 382 | p->mg = alloc_migration(cache); |
| 357 | if (!p->mg) | 383 | if (!p->mg) |
| 358 | return -ENOMEM; | 384 | return -ENOMEM; |
| 359 | } | 385 | } |
| @@ -382,7 +408,7 @@ static void prealloc_free_structs(struct cache *cache, struct prealloc *p) | |||
| 382 | free_prison_cell(cache, p->cell1); | 408 | free_prison_cell(cache, p->cell1); |
| 383 | 409 | ||
| 384 | if (p->mg) | 410 | if (p->mg) |
| 385 | mempool_free(p->mg, cache->migration_pool); | 411 | free_migration(p->mg); |
| 386 | } | 412 | } |
| 387 | 413 | ||
| 388 | static struct dm_cache_migration *prealloc_get_migration(struct prealloc *p) | 414 | static struct dm_cache_migration *prealloc_get_migration(struct prealloc *p) |
| @@ -854,24 +880,14 @@ static void remap_to_origin_then_cache(struct cache *cache, struct bio *bio, | |||
| 854 | * Migration covers moving data from the origin device to the cache, or | 880 | * Migration covers moving data from the origin device to the cache, or |
| 855 | * vice versa. | 881 | * vice versa. |
| 856 | *--------------------------------------------------------------*/ | 882 | *--------------------------------------------------------------*/ |
| 857 | static void free_migration(struct dm_cache_migration *mg) | 883 | static void inc_io_migrations(struct cache *cache) |
| 858 | { | ||
| 859 | mempool_free(mg, mg->cache->migration_pool); | ||
| 860 | } | ||
| 861 | |||
| 862 | static void inc_nr_migrations(struct cache *cache) | ||
| 863 | { | 884 | { |
| 864 | atomic_inc(&cache->nr_migrations); | 885 | atomic_inc(&cache->nr_io_migrations); |
| 865 | } | 886 | } |
| 866 | 887 | ||
| 867 | static void dec_nr_migrations(struct cache *cache) | 888 | static void dec_io_migrations(struct cache *cache) |
| 868 | { | 889 | { |
| 869 | atomic_dec(&cache->nr_migrations); | 890 | atomic_dec(&cache->nr_io_migrations); |
| 870 | |||
| 871 | /* | ||
| 872 | * Wake the worker in case we're suspending the target. | ||
| 873 | */ | ||
| 874 | wake_up(&cache->migration_wait); | ||
| 875 | } | 891 | } |
| 876 | 892 | ||
| 877 | static void __cell_defer(struct cache *cache, struct dm_bio_prison_cell *cell, | 893 | static void __cell_defer(struct cache *cache, struct dm_bio_prison_cell *cell, |
| @@ -894,11 +910,10 @@ static void cell_defer(struct cache *cache, struct dm_bio_prison_cell *cell, | |||
| 894 | wake_worker(cache); | 910 | wake_worker(cache); |
| 895 | } | 911 | } |
| 896 | 912 | ||
| 897 | static void cleanup_migration(struct dm_cache_migration *mg) | 913 | static void free_io_migration(struct dm_cache_migration *mg) |
| 898 | { | 914 | { |
| 899 | struct cache *cache = mg->cache; | 915 | dec_io_migrations(mg->cache); |
| 900 | free_migration(mg); | 916 | free_migration(mg); |
| 901 | dec_nr_migrations(cache); | ||
| 902 | } | 917 | } |
| 903 | 918 | ||
| 904 | static void migration_failure(struct dm_cache_migration *mg) | 919 | static void migration_failure(struct dm_cache_migration *mg) |
| @@ -923,7 +938,7 @@ static void migration_failure(struct dm_cache_migration *mg) | |||
| 923 | cell_defer(cache, mg->new_ocell, true); | 938 | cell_defer(cache, mg->new_ocell, true); |
| 924 | } | 939 | } |
| 925 | 940 | ||
| 926 | cleanup_migration(mg); | 941 | free_io_migration(mg); |
| 927 | } | 942 | } |
| 928 | 943 | ||
| 929 | static void migration_success_pre_commit(struct dm_cache_migration *mg) | 944 | static void migration_success_pre_commit(struct dm_cache_migration *mg) |
| @@ -934,7 +949,7 @@ static void migration_success_pre_commit(struct dm_cache_migration *mg) | |||
| 934 | if (mg->writeback) { | 949 | if (mg->writeback) { |
| 935 | clear_dirty(cache, mg->old_oblock, mg->cblock); | 950 | clear_dirty(cache, mg->old_oblock, mg->cblock); |
| 936 | cell_defer(cache, mg->old_ocell, false); | 951 | cell_defer(cache, mg->old_ocell, false); |
| 937 | cleanup_migration(mg); | 952 | free_io_migration(mg); |
| 938 | return; | 953 | return; |
| 939 | 954 | ||
| 940 | } else if (mg->demote) { | 955 | } else if (mg->demote) { |
| @@ -944,14 +959,14 @@ static void migration_success_pre_commit(struct dm_cache_migration *mg) | |||
| 944 | mg->old_oblock); | 959 | mg->old_oblock); |
| 945 | if (mg->promote) | 960 | if (mg->promote) |
| 946 | cell_defer(cache, mg->new_ocell, true); | 961 | cell_defer(cache, mg->new_ocell, true); |
| 947 | cleanup_migration(mg); | 962 | free_io_migration(mg); |
| 948 | return; | 963 | return; |
| 949 | } | 964 | } |
| 950 | } else { | 965 | } else { |
| 951 | if (dm_cache_insert_mapping(cache->cmd, mg->cblock, mg->new_oblock)) { | 966 | if (dm_cache_insert_mapping(cache->cmd, mg->cblock, mg->new_oblock)) { |
| 952 | DMWARN_LIMIT("promotion failed; couldn't update on disk metadata"); | 967 | DMWARN_LIMIT("promotion failed; couldn't update on disk metadata"); |
| 953 | policy_remove_mapping(cache->policy, mg->new_oblock); | 968 | policy_remove_mapping(cache->policy, mg->new_oblock); |
| 954 | cleanup_migration(mg); | 969 | free_io_migration(mg); |
| 955 | return; | 970 | return; |
| 956 | } | 971 | } |
| 957 | } | 972 | } |
| @@ -984,7 +999,7 @@ static void migration_success_post_commit(struct dm_cache_migration *mg) | |||
| 984 | } else { | 999 | } else { |
| 985 | if (mg->invalidate) | 1000 | if (mg->invalidate) |
| 986 | policy_remove_mapping(cache->policy, mg->old_oblock); | 1001 | policy_remove_mapping(cache->policy, mg->old_oblock); |
| 987 | cleanup_migration(mg); | 1002 | free_io_migration(mg); |
| 988 | } | 1003 | } |
| 989 | 1004 | ||
| 990 | } else { | 1005 | } else { |
| @@ -999,7 +1014,7 @@ static void migration_success_post_commit(struct dm_cache_migration *mg) | |||
| 999 | bio_endio(mg->new_ocell->holder, 0); | 1014 | bio_endio(mg->new_ocell->holder, 0); |
| 1000 | cell_defer(cache, mg->new_ocell, false); | 1015 | cell_defer(cache, mg->new_ocell, false); |
| 1001 | } | 1016 | } |
| 1002 | cleanup_migration(mg); | 1017 | free_io_migration(mg); |
| 1003 | } | 1018 | } |
| 1004 | } | 1019 | } |
| 1005 | 1020 | ||
| @@ -1251,7 +1266,7 @@ static void promote(struct cache *cache, struct prealloc *structs, | |||
| 1251 | mg->new_ocell = cell; | 1266 | mg->new_ocell = cell; |
| 1252 | mg->start_jiffies = jiffies; | 1267 | mg->start_jiffies = jiffies; |
| 1253 | 1268 | ||
| 1254 | inc_nr_migrations(cache); | 1269 | inc_io_migrations(cache); |
| 1255 | quiesce_migration(mg); | 1270 | quiesce_migration(mg); |
| 1256 | } | 1271 | } |
| 1257 | 1272 | ||
| @@ -1275,7 +1290,7 @@ static void writeback(struct cache *cache, struct prealloc *structs, | |||
| 1275 | mg->new_ocell = NULL; | 1290 | mg->new_ocell = NULL; |
| 1276 | mg->start_jiffies = jiffies; | 1291 | mg->start_jiffies = jiffies; |
| 1277 | 1292 | ||
| 1278 | inc_nr_migrations(cache); | 1293 | inc_io_migrations(cache); |
| 1279 | quiesce_migration(mg); | 1294 | quiesce_migration(mg); |
| 1280 | } | 1295 | } |
| 1281 | 1296 | ||
| @@ -1302,7 +1317,7 @@ static void demote_then_promote(struct cache *cache, struct prealloc *structs, | |||
| 1302 | mg->new_ocell = new_ocell; | 1317 | mg->new_ocell = new_ocell; |
| 1303 | mg->start_jiffies = jiffies; | 1318 | mg->start_jiffies = jiffies; |
| 1304 | 1319 | ||
| 1305 | inc_nr_migrations(cache); | 1320 | inc_io_migrations(cache); |
| 1306 | quiesce_migration(mg); | 1321 | quiesce_migration(mg); |
| 1307 | } | 1322 | } |
| 1308 | 1323 | ||
| @@ -1330,7 +1345,7 @@ static void invalidate(struct cache *cache, struct prealloc *structs, | |||
| 1330 | mg->new_ocell = NULL; | 1345 | mg->new_ocell = NULL; |
| 1331 | mg->start_jiffies = jiffies; | 1346 | mg->start_jiffies = jiffies; |
| 1332 | 1347 | ||
| 1333 | inc_nr_migrations(cache); | 1348 | inc_io_migrations(cache); |
| 1334 | quiesce_migration(mg); | 1349 | quiesce_migration(mg); |
| 1335 | } | 1350 | } |
| 1336 | 1351 | ||
| @@ -1412,7 +1427,7 @@ static void process_discard_bio(struct cache *cache, struct prealloc *structs, | |||
| 1412 | 1427 | ||
| 1413 | static bool spare_migration_bandwidth(struct cache *cache) | 1428 | static bool spare_migration_bandwidth(struct cache *cache) |
| 1414 | { | 1429 | { |
| 1415 | sector_t current_volume = (atomic_read(&cache->nr_migrations) + 1) * | 1430 | sector_t current_volume = (atomic_read(&cache->nr_io_migrations) + 1) * |
| 1416 | cache->sectors_per_block; | 1431 | cache->sectors_per_block; |
| 1417 | return current_volume < cache->migration_threshold; | 1432 | return current_volume < cache->migration_threshold; |
| 1418 | } | 1433 | } |
| @@ -1764,7 +1779,7 @@ static void stop_quiescing(struct cache *cache) | |||
| 1764 | 1779 | ||
| 1765 | static void wait_for_migrations(struct cache *cache) | 1780 | static void wait_for_migrations(struct cache *cache) |
| 1766 | { | 1781 | { |
| 1767 | wait_event(cache->migration_wait, !atomic_read(&cache->nr_migrations)); | 1782 | wait_event(cache->migration_wait, !atomic_read(&cache->nr_allocated_migrations)); |
| 1768 | } | 1783 | } |
| 1769 | 1784 | ||
| 1770 | static void stop_worker(struct cache *cache) | 1785 | static void stop_worker(struct cache *cache) |
| @@ -1876,9 +1891,6 @@ static void destroy(struct cache *cache) | |||
| 1876 | { | 1891 | { |
| 1877 | unsigned i; | 1892 | unsigned i; |
| 1878 | 1893 | ||
| 1879 | if (cache->next_migration) | ||
| 1880 | mempool_free(cache->next_migration, cache->migration_pool); | ||
| 1881 | |||
| 1882 | if (cache->migration_pool) | 1894 | if (cache->migration_pool) |
| 1883 | mempool_destroy(cache->migration_pool); | 1895 | mempool_destroy(cache->migration_pool); |
| 1884 | 1896 | ||
| @@ -2424,7 +2436,8 @@ static int cache_create(struct cache_args *ca, struct cache **result) | |||
| 2424 | INIT_LIST_HEAD(&cache->quiesced_migrations); | 2436 | INIT_LIST_HEAD(&cache->quiesced_migrations); |
| 2425 | INIT_LIST_HEAD(&cache->completed_migrations); | 2437 | INIT_LIST_HEAD(&cache->completed_migrations); |
| 2426 | INIT_LIST_HEAD(&cache->need_commit_migrations); | 2438 | INIT_LIST_HEAD(&cache->need_commit_migrations); |
| 2427 | atomic_set(&cache->nr_migrations, 0); | 2439 | atomic_set(&cache->nr_allocated_migrations, 0); |
| 2440 | atomic_set(&cache->nr_io_migrations, 0); | ||
| 2428 | init_waitqueue_head(&cache->migration_wait); | 2441 | init_waitqueue_head(&cache->migration_wait); |
| 2429 | 2442 | ||
| 2430 | init_waitqueue_head(&cache->quiescing_wait); | 2443 | init_waitqueue_head(&cache->quiescing_wait); |
| @@ -2487,8 +2500,6 @@ static int cache_create(struct cache_args *ca, struct cache **result) | |||
| 2487 | goto bad; | 2500 | goto bad; |
| 2488 | } | 2501 | } |
| 2489 | 2502 | ||
| 2490 | cache->next_migration = NULL; | ||
| 2491 | |||
| 2492 | cache->need_tick_bio = true; | 2503 | cache->need_tick_bio = true; |
| 2493 | cache->sized = false; | 2504 | cache->sized = false; |
| 2494 | cache->invalidate = false; | 2505 | cache->invalidate = false; |
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index b98cd9d84435..2caf5b374649 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
| @@ -206,6 +206,9 @@ struct mapped_device { | |||
| 206 | /* zero-length flush that will be cloned and submitted to targets */ | 206 | /* zero-length flush that will be cloned and submitted to targets */ |
| 207 | struct bio flush_bio; | 207 | struct bio flush_bio; |
| 208 | 208 | ||
| 209 | /* the number of internal suspends */ | ||
| 210 | unsigned internal_suspend_count; | ||
| 211 | |||
| 209 | struct dm_stats stats; | 212 | struct dm_stats stats; |
| 210 | }; | 213 | }; |
| 211 | 214 | ||
| @@ -2928,7 +2931,7 @@ static void __dm_internal_suspend(struct mapped_device *md, unsigned suspend_fla | |||
| 2928 | { | 2931 | { |
| 2929 | struct dm_table *map = NULL; | 2932 | struct dm_table *map = NULL; |
| 2930 | 2933 | ||
| 2931 | if (dm_suspended_internally_md(md)) | 2934 | if (md->internal_suspend_count++) |
| 2932 | return; /* nested internal suspend */ | 2935 | return; /* nested internal suspend */ |
| 2933 | 2936 | ||
| 2934 | if (dm_suspended_md(md)) { | 2937 | if (dm_suspended_md(md)) { |
| @@ -2953,7 +2956,9 @@ static void __dm_internal_suspend(struct mapped_device *md, unsigned suspend_fla | |||
| 2953 | 2956 | ||
| 2954 | static void __dm_internal_resume(struct mapped_device *md) | 2957 | static void __dm_internal_resume(struct mapped_device *md) |
| 2955 | { | 2958 | { |
| 2956 | if (!dm_suspended_internally_md(md)) | 2959 | BUG_ON(!md->internal_suspend_count); |
| 2960 | |||
| 2961 | if (--md->internal_suspend_count) | ||
| 2957 | return; /* resume from nested internal suspend */ | 2962 | return; /* resume from nested internal suspend */ |
| 2958 | 2963 | ||
| 2959 | if (dm_suspended_md(md)) | 2964 | if (dm_suspended_md(md)) |
