diff options
Diffstat (limited to 'drivers/md/dm.c')
-rw-r--r-- | drivers/md/dm.c | 96 |
1 files changed, 56 insertions, 40 deletions
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 243ff6884e83..f6b03957efc7 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -97,6 +97,7 @@ struct mapped_device { | |||
97 | * freeze/thaw support require holding onto a super block | 97 | * freeze/thaw support require holding onto a super block |
98 | */ | 98 | */ |
99 | struct super_block *frozen_sb; | 99 | struct super_block *frozen_sb; |
100 | struct block_device *frozen_bdev; | ||
100 | }; | 101 | }; |
101 | 102 | ||
102 | #define MIN_IOS 256 | 103 | #define MIN_IOS 256 |
@@ -990,44 +991,50 @@ int dm_swap_table(struct mapped_device *md, struct dm_table *table) | |||
990 | */ | 991 | */ |
991 | static int __lock_fs(struct mapped_device *md) | 992 | static int __lock_fs(struct mapped_device *md) |
992 | { | 993 | { |
993 | struct block_device *bdev; | 994 | int error = -ENOMEM; |
994 | 995 | ||
995 | if (test_and_set_bit(DMF_FS_LOCKED, &md->flags)) | 996 | if (test_and_set_bit(DMF_FS_LOCKED, &md->flags)) |
996 | return 0; | 997 | return 0; |
997 | 998 | ||
998 | bdev = bdget_disk(md->disk, 0); | 999 | md->frozen_bdev = bdget_disk(md->disk, 0); |
999 | if (!bdev) { | 1000 | if (!md->frozen_bdev) { |
1000 | DMWARN("bdget failed in __lock_fs"); | 1001 | DMWARN("bdget failed in __lock_fs"); |
1001 | return -ENOMEM; | 1002 | goto out; |
1002 | } | 1003 | } |
1003 | 1004 | ||
1004 | WARN_ON(md->frozen_sb); | 1005 | WARN_ON(md->frozen_sb); |
1005 | md->frozen_sb = freeze_bdev(bdev); | 1006 | |
1007 | md->frozen_sb = freeze_bdev(md->frozen_bdev); | ||
1008 | if (IS_ERR(md->frozen_sb)) { | ||
1009 | error = PTR_ERR(md->frozen_sb); | ||
1010 | goto out_bdput; | ||
1011 | } | ||
1012 | |||
1006 | /* don't bdput right now, we don't want the bdev | 1013 | /* don't bdput right now, we don't want the bdev |
1007 | * to go away while it is locked. We'll bdput | 1014 | * to go away while it is locked. We'll bdput |
1008 | * in __unlock_fs | 1015 | * in __unlock_fs |
1009 | */ | 1016 | */ |
1010 | return 0; | 1017 | return 0; |
1018 | |||
1019 | out_bdput: | ||
1020 | bdput(md->frozen_bdev); | ||
1021 | md->frozen_sb = NULL; | ||
1022 | md->frozen_bdev = NULL; | ||
1023 | out: | ||
1024 | clear_bit(DMF_FS_LOCKED, &md->flags); | ||
1025 | return error; | ||
1011 | } | 1026 | } |
1012 | 1027 | ||
1013 | static int __unlock_fs(struct mapped_device *md) | 1028 | static void __unlock_fs(struct mapped_device *md) |
1014 | { | 1029 | { |
1015 | struct block_device *bdev; | ||
1016 | |||
1017 | if (!test_and_clear_bit(DMF_FS_LOCKED, &md->flags)) | 1030 | if (!test_and_clear_bit(DMF_FS_LOCKED, &md->flags)) |
1018 | return 0; | 1031 | return; |
1019 | 1032 | ||
1020 | bdev = bdget_disk(md->disk, 0); | 1033 | thaw_bdev(md->frozen_bdev, md->frozen_sb); |
1021 | if (!bdev) { | 1034 | bdput(md->frozen_bdev); |
1022 | DMWARN("bdget failed in __unlock_fs"); | ||
1023 | return -ENOMEM; | ||
1024 | } | ||
1025 | 1035 | ||
1026 | thaw_bdev(bdev, md->frozen_sb); | ||
1027 | md->frozen_sb = NULL; | 1036 | md->frozen_sb = NULL; |
1028 | bdput(bdev); | 1037 | md->frozen_bdev = NULL; |
1029 | bdput(bdev); | ||
1030 | return 0; | ||
1031 | } | 1038 | } |
1032 | 1039 | ||
1033 | /* | 1040 | /* |
@@ -1041,37 +1048,37 @@ int dm_suspend(struct mapped_device *md) | |||
1041 | { | 1048 | { |
1042 | struct dm_table *map; | 1049 | struct dm_table *map; |
1043 | DECLARE_WAITQUEUE(wait, current); | 1050 | DECLARE_WAITQUEUE(wait, current); |
1051 | int error = -EINVAL; | ||
1044 | 1052 | ||
1045 | /* Flush I/O to the device. */ | 1053 | /* Flush I/O to the device. */ |
1046 | down_read(&md->lock); | 1054 | down_read(&md->lock); |
1047 | if (test_bit(DMF_BLOCK_IO, &md->flags)) { | 1055 | if (test_bit(DMF_BLOCK_IO, &md->flags)) |
1048 | up_read(&md->lock); | 1056 | goto out_read_unlock; |
1049 | return -EINVAL; | 1057 | |
1050 | } | 1058 | error = __lock_fs(md); |
1059 | if (error) | ||
1060 | goto out_read_unlock; | ||
1051 | 1061 | ||
1052 | map = dm_get_table(md); | 1062 | map = dm_get_table(md); |
1053 | if (map) | 1063 | if (map) |
1054 | dm_table_presuspend_targets(map); | 1064 | dm_table_presuspend_targets(map); |
1055 | __lock_fs(md); | ||
1056 | 1065 | ||
1057 | up_read(&md->lock); | 1066 | up_read(&md->lock); |
1058 | 1067 | ||
1059 | /* | 1068 | /* |
1060 | * First we set the BLOCK_IO flag so no more ios will be | 1069 | * First we set the BLOCK_IO flag so no more ios will be mapped. |
1061 | * mapped. | 1070 | * |
1071 | * If the flag is already set we know another thread is trying to | ||
1072 | * suspend as well, so we leave the fs locked for this thread. | ||
1062 | */ | 1073 | */ |
1074 | error = -EINVAL; | ||
1063 | down_write(&md->lock); | 1075 | down_write(&md->lock); |
1064 | if (test_bit(DMF_BLOCK_IO, &md->flags)) { | 1076 | if (test_and_set_bit(DMF_BLOCK_IO, &md->flags)) { |
1065 | /* | 1077 | if (map) |
1066 | * If we get here we know another thread is | 1078 | dm_table_put(map); |
1067 | * trying to suspend as well, so we leave the fs | 1079 | goto out_write_unlock; |
1068 | * locked for this thread. | ||
1069 | */ | ||
1070 | up_write(&md->lock); | ||
1071 | return -EINVAL; | ||
1072 | } | 1080 | } |
1073 | 1081 | ||
1074 | set_bit(DMF_BLOCK_IO, &md->flags); | ||
1075 | add_wait_queue(&md->wait, &wait); | 1082 | add_wait_queue(&md->wait, &wait); |
1076 | up_write(&md->lock); | 1083 | up_write(&md->lock); |
1077 | 1084 | ||
@@ -1099,12 +1106,9 @@ int dm_suspend(struct mapped_device *md) | |||
1099 | remove_wait_queue(&md->wait, &wait); | 1106 | remove_wait_queue(&md->wait, &wait); |
1100 | 1107 | ||
1101 | /* were we interrupted ? */ | 1108 | /* were we interrupted ? */ |
1102 | if (atomic_read(&md->pending)) { | 1109 | error = -EINTR; |
1103 | __unlock_fs(md); | 1110 | if (atomic_read(&md->pending)) |
1104 | clear_bit(DMF_BLOCK_IO, &md->flags); | 1111 | goto out_unfreeze; |
1105 | up_write(&md->lock); | ||
1106 | return -EINTR; | ||
1107 | } | ||
1108 | 1112 | ||
1109 | set_bit(DMF_SUSPENDED, &md->flags); | 1113 | set_bit(DMF_SUSPENDED, &md->flags); |
1110 | 1114 | ||
@@ -1115,6 +1119,18 @@ int dm_suspend(struct mapped_device *md) | |||
1115 | up_write(&md->lock); | 1119 | up_write(&md->lock); |
1116 | 1120 | ||
1117 | return 0; | 1121 | return 0; |
1122 | |||
1123 | out_unfreeze: | ||
1124 | /* FIXME Undo dm_table_presuspend_targets */ | ||
1125 | __unlock_fs(md); | ||
1126 | clear_bit(DMF_BLOCK_IO, &md->flags); | ||
1127 | out_write_unlock: | ||
1128 | up_write(&md->lock); | ||
1129 | return error; | ||
1130 | |||
1131 | out_read_unlock: | ||
1132 | up_read(&md->lock); | ||
1133 | return error; | ||
1118 | } | 1134 | } |
1119 | 1135 | ||
1120 | int dm_resume(struct mapped_device *md) | 1136 | int dm_resume(struct mapped_device *md) |