diff options
Diffstat (limited to 'drivers/md/dm.c')
-rw-r--r-- | drivers/md/dm.c | 95 |
1 files changed, 61 insertions, 34 deletions
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 930b9fc27953..0e481512f918 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -55,6 +55,7 @@ union map_info *dm_get_mapinfo(struct bio *bio) | |||
55 | */ | 55 | */ |
56 | #define DMF_BLOCK_IO 0 | 56 | #define DMF_BLOCK_IO 0 |
57 | #define DMF_SUSPENDED 1 | 57 | #define DMF_SUSPENDED 1 |
58 | #define DMF_FROZEN 2 | ||
58 | 59 | ||
59 | struct mapped_device { | 60 | struct mapped_device { |
60 | struct rw_semaphore io_lock; | 61 | struct rw_semaphore io_lock; |
@@ -97,7 +98,7 @@ struct mapped_device { | |||
97 | * freeze/thaw support require holding onto a super block | 98 | * freeze/thaw support require holding onto a super block |
98 | */ | 99 | */ |
99 | struct super_block *frozen_sb; | 100 | struct super_block *frozen_sb; |
100 | struct block_device *frozen_bdev; | 101 | struct block_device *suspended_bdev; |
101 | }; | 102 | }; |
102 | 103 | ||
103 | #define MIN_IOS 256 | 104 | #define MIN_IOS 256 |
@@ -836,9 +837,9 @@ static void __set_size(struct mapped_device *md, sector_t size) | |||
836 | { | 837 | { |
837 | set_capacity(md->disk, size); | 838 | set_capacity(md->disk, size); |
838 | 839 | ||
839 | down(&md->frozen_bdev->bd_inode->i_sem); | 840 | down(&md->suspended_bdev->bd_inode->i_sem); |
840 | i_size_write(md->frozen_bdev->bd_inode, (loff_t)size << SECTOR_SHIFT); | 841 | i_size_write(md->suspended_bdev->bd_inode, (loff_t)size << SECTOR_SHIFT); |
841 | up(&md->frozen_bdev->bd_inode->i_sem); | 842 | up(&md->suspended_bdev->bd_inode->i_sem); |
842 | } | 843 | } |
843 | 844 | ||
844 | static int __bind(struct mapped_device *md, struct dm_table *t) | 845 | static int __bind(struct mapped_device *md, struct dm_table *t) |
@@ -902,10 +903,9 @@ int dm_create_with_minor(unsigned int minor, struct mapped_device **result) | |||
902 | return create_aux(minor, 1, result); | 903 | return create_aux(minor, 1, result); |
903 | } | 904 | } |
904 | 905 | ||
905 | void *dm_get_mdptr(dev_t dev) | 906 | static struct mapped_device *dm_find_md(dev_t dev) |
906 | { | 907 | { |
907 | struct mapped_device *md; | 908 | struct mapped_device *md; |
908 | void *mdptr = NULL; | ||
909 | unsigned minor = MINOR(dev); | 909 | unsigned minor = MINOR(dev); |
910 | 910 | ||
911 | if (MAJOR(dev) != _major || minor >= (1 << MINORBITS)) | 911 | if (MAJOR(dev) != _major || minor >= (1 << MINORBITS)) |
@@ -914,12 +914,32 @@ void *dm_get_mdptr(dev_t dev) | |||
914 | down(&_minor_lock); | 914 | down(&_minor_lock); |
915 | 915 | ||
916 | md = idr_find(&_minor_idr, minor); | 916 | md = idr_find(&_minor_idr, minor); |
917 | 917 | if (!md || (dm_disk(md)->first_minor != minor)) | |
918 | if (md && (dm_disk(md)->first_minor == minor)) | 918 | md = NULL; |
919 | mdptr = md->interface_ptr; | ||
920 | 919 | ||
921 | up(&_minor_lock); | 920 | up(&_minor_lock); |
922 | 921 | ||
922 | return md; | ||
923 | } | ||
924 | |||
925 | struct mapped_device *dm_get_md(dev_t dev) | ||
926 | { | ||
927 | struct mapped_device *md = dm_find_md(dev); | ||
928 | |||
929 | if (md) | ||
930 | dm_get(md); | ||
931 | |||
932 | return md; | ||
933 | } | ||
934 | |||
935 | void *dm_get_mdptr(dev_t dev) | ||
936 | { | ||
937 | struct mapped_device *md; | ||
938 | void *mdptr = NULL; | ||
939 | |||
940 | md = dm_find_md(dev); | ||
941 | if (md) | ||
942 | mdptr = md->interface_ptr; | ||
923 | return mdptr; | 943 | return mdptr; |
924 | } | 944 | } |
925 | 945 | ||
@@ -991,43 +1011,33 @@ out: | |||
991 | */ | 1011 | */ |
992 | static int lock_fs(struct mapped_device *md) | 1012 | static int lock_fs(struct mapped_device *md) |
993 | { | 1013 | { |
994 | int r = -ENOMEM; | 1014 | int r; |
995 | |||
996 | md->frozen_bdev = bdget_disk(md->disk, 0); | ||
997 | if (!md->frozen_bdev) { | ||
998 | DMWARN("bdget failed in lock_fs"); | ||
999 | goto out; | ||
1000 | } | ||
1001 | 1015 | ||
1002 | WARN_ON(md->frozen_sb); | 1016 | WARN_ON(md->frozen_sb); |
1003 | 1017 | ||
1004 | md->frozen_sb = freeze_bdev(md->frozen_bdev); | 1018 | md->frozen_sb = freeze_bdev(md->suspended_bdev); |
1005 | if (IS_ERR(md->frozen_sb)) { | 1019 | if (IS_ERR(md->frozen_sb)) { |
1006 | r = PTR_ERR(md->frozen_sb); | 1020 | r = PTR_ERR(md->frozen_sb); |
1007 | goto out_bdput; | 1021 | md->frozen_sb = NULL; |
1022 | return r; | ||
1008 | } | 1023 | } |
1009 | 1024 | ||
1025 | set_bit(DMF_FROZEN, &md->flags); | ||
1026 | |||
1010 | /* don't bdput right now, we don't want the bdev | 1027 | /* don't bdput right now, we don't want the bdev |
1011 | * to go away while it is locked. We'll bdput | 1028 | * to go away while it is locked. |
1012 | * in unlock_fs | ||
1013 | */ | 1029 | */ |
1014 | return 0; | 1030 | return 0; |
1015 | |||
1016 | out_bdput: | ||
1017 | bdput(md->frozen_bdev); | ||
1018 | md->frozen_sb = NULL; | ||
1019 | md->frozen_bdev = NULL; | ||
1020 | out: | ||
1021 | return r; | ||
1022 | } | 1031 | } |
1023 | 1032 | ||
1024 | static void unlock_fs(struct mapped_device *md) | 1033 | static void unlock_fs(struct mapped_device *md) |
1025 | { | 1034 | { |
1026 | thaw_bdev(md->frozen_bdev, md->frozen_sb); | 1035 | if (!test_bit(DMF_FROZEN, &md->flags)) |
1027 | bdput(md->frozen_bdev); | 1036 | return; |
1028 | 1037 | ||
1038 | thaw_bdev(md->suspended_bdev, md->frozen_sb); | ||
1029 | md->frozen_sb = NULL; | 1039 | md->frozen_sb = NULL; |
1030 | md->frozen_bdev = NULL; | 1040 | clear_bit(DMF_FROZEN, &md->flags); |
1031 | } | 1041 | } |
1032 | 1042 | ||
1033 | /* | 1043 | /* |
@@ -1037,7 +1047,7 @@ static void unlock_fs(struct mapped_device *md) | |||
1037 | * dm_bind_table, dm_suspend must be called to flush any in | 1047 | * dm_bind_table, dm_suspend must be called to flush any in |
1038 | * flight bios and ensure that any further io gets deferred. | 1048 | * flight bios and ensure that any further io gets deferred. |
1039 | */ | 1049 | */ |
1040 | int dm_suspend(struct mapped_device *md) | 1050 | int dm_suspend(struct mapped_device *md, int do_lockfs) |
1041 | { | 1051 | { |
1042 | struct dm_table *map = NULL; | 1052 | struct dm_table *map = NULL; |
1043 | DECLARE_WAITQUEUE(wait, current); | 1053 | DECLARE_WAITQUEUE(wait, current); |
@@ -1053,10 +1063,19 @@ int dm_suspend(struct mapped_device *md) | |||
1053 | /* This does not get reverted if there's an error later. */ | 1063 | /* This does not get reverted if there's an error later. */ |
1054 | dm_table_presuspend_targets(map); | 1064 | dm_table_presuspend_targets(map); |
1055 | 1065 | ||
1056 | /* Flush I/O to the device. */ | 1066 | md->suspended_bdev = bdget_disk(md->disk, 0); |
1057 | r = lock_fs(md); | 1067 | if (!md->suspended_bdev) { |
1058 | if (r) | 1068 | DMWARN("bdget failed in dm_suspend"); |
1069 | r = -ENOMEM; | ||
1059 | goto out; | 1070 | goto out; |
1071 | } | ||
1072 | |||
1073 | /* Flush I/O to the device. */ | ||
1074 | if (do_lockfs) { | ||
1075 | r = lock_fs(md); | ||
1076 | if (r) | ||
1077 | goto out; | ||
1078 | } | ||
1060 | 1079 | ||
1061 | /* | 1080 | /* |
1062 | * First we set the BLOCK_IO flag so no more ios will be mapped. | 1081 | * First we set the BLOCK_IO flag so no more ios will be mapped. |
@@ -1105,6 +1124,11 @@ int dm_suspend(struct mapped_device *md) | |||
1105 | r = 0; | 1124 | r = 0; |
1106 | 1125 | ||
1107 | out: | 1126 | out: |
1127 | if (r && md->suspended_bdev) { | ||
1128 | bdput(md->suspended_bdev); | ||
1129 | md->suspended_bdev = NULL; | ||
1130 | } | ||
1131 | |||
1108 | dm_table_put(map); | 1132 | dm_table_put(map); |
1109 | up(&md->suspend_lock); | 1133 | up(&md->suspend_lock); |
1110 | return r; | 1134 | return r; |
@@ -1135,6 +1159,9 @@ int dm_resume(struct mapped_device *md) | |||
1135 | 1159 | ||
1136 | unlock_fs(md); | 1160 | unlock_fs(md); |
1137 | 1161 | ||
1162 | bdput(md->suspended_bdev); | ||
1163 | md->suspended_bdev = NULL; | ||
1164 | |||
1138 | clear_bit(DMF_SUSPENDED, &md->flags); | 1165 | clear_bit(DMF_SUSPENDED, &md->flags); |
1139 | 1166 | ||
1140 | dm_table_unplug_all(map); | 1167 | dm_table_unplug_all(map); |