aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md/dm.c')
-rw-r--r--drivers/md/dm.c96
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 */
991static int __lock_fs(struct mapped_device *md) 992static 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
1019out_bdput:
1020 bdput(md->frozen_bdev);
1021 md->frozen_sb = NULL;
1022 md->frozen_bdev = NULL;
1023out:
1024 clear_bit(DMF_FS_LOCKED, &md->flags);
1025 return error;
1011} 1026}
1012 1027
1013static int __unlock_fs(struct mapped_device *md) 1028static 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
1123out_unfreeze:
1124 /* FIXME Undo dm_table_presuspend_targets */
1125 __unlock_fs(md);
1126 clear_bit(DMF_BLOCK_IO, &md->flags);
1127out_write_unlock:
1128 up_write(&md->lock);
1129 return error;
1130
1131out_read_unlock:
1132 up_read(&md->lock);
1133 return error;
1118} 1134}
1119 1135
1120int dm_resume(struct mapped_device *md) 1136int dm_resume(struct mapped_device *md)