diff options
Diffstat (limited to 'drivers/md/dm.c')
-rw-r--r-- | drivers/md/dm.c | 196 |
1 files changed, 89 insertions, 107 deletions
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 54fabbf06678..d487d9deb98e 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -55,10 +55,10 @@ 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_FS_LOCKED 2 | ||
59 | 58 | ||
60 | struct mapped_device { | 59 | struct mapped_device { |
61 | struct rw_semaphore lock; | 60 | struct rw_semaphore io_lock; |
61 | struct semaphore suspend_lock; | ||
62 | rwlock_t map_lock; | 62 | rwlock_t map_lock; |
63 | atomic_t holders; | 63 | atomic_t holders; |
64 | 64 | ||
@@ -248,16 +248,16 @@ static inline void free_tio(struct mapped_device *md, struct target_io *tio) | |||
248 | */ | 248 | */ |
249 | static int queue_io(struct mapped_device *md, struct bio *bio) | 249 | static int queue_io(struct mapped_device *md, struct bio *bio) |
250 | { | 250 | { |
251 | down_write(&md->lock); | 251 | down_write(&md->io_lock); |
252 | 252 | ||
253 | if (!test_bit(DMF_BLOCK_IO, &md->flags)) { | 253 | if (!test_bit(DMF_BLOCK_IO, &md->flags)) { |
254 | up_write(&md->lock); | 254 | up_write(&md->io_lock); |
255 | return 1; | 255 | return 1; |
256 | } | 256 | } |
257 | 257 | ||
258 | bio_list_add(&md->deferred, bio); | 258 | bio_list_add(&md->deferred, bio); |
259 | 259 | ||
260 | up_write(&md->lock); | 260 | up_write(&md->io_lock); |
261 | return 0; /* deferred successfully */ | 261 | return 0; /* deferred successfully */ |
262 | } | 262 | } |
263 | 263 | ||
@@ -568,14 +568,14 @@ static int dm_request(request_queue_t *q, struct bio *bio) | |||
568 | int r; | 568 | int r; |
569 | struct mapped_device *md = q->queuedata; | 569 | struct mapped_device *md = q->queuedata; |
570 | 570 | ||
571 | down_read(&md->lock); | 571 | down_read(&md->io_lock); |
572 | 572 | ||
573 | /* | 573 | /* |
574 | * If we're suspended we have to queue | 574 | * If we're suspended we have to queue |
575 | * this io for later. | 575 | * this io for later. |
576 | */ | 576 | */ |
577 | while (test_bit(DMF_BLOCK_IO, &md->flags)) { | 577 | while (test_bit(DMF_BLOCK_IO, &md->flags)) { |
578 | up_read(&md->lock); | 578 | up_read(&md->io_lock); |
579 | 579 | ||
580 | if (bio_rw(bio) == READA) { | 580 | if (bio_rw(bio) == READA) { |
581 | bio_io_error(bio, bio->bi_size); | 581 | bio_io_error(bio, bio->bi_size); |
@@ -594,11 +594,11 @@ static int dm_request(request_queue_t *q, struct bio *bio) | |||
594 | * We're in a while loop, because someone could suspend | 594 | * We're in a while loop, because someone could suspend |
595 | * before we get to the following read lock. | 595 | * before we get to the following read lock. |
596 | */ | 596 | */ |
597 | down_read(&md->lock); | 597 | down_read(&md->io_lock); |
598 | } | 598 | } |
599 | 599 | ||
600 | __split_bio(md, bio); | 600 | __split_bio(md, bio); |
601 | up_read(&md->lock); | 601 | up_read(&md->io_lock); |
602 | return 0; | 602 | return 0; |
603 | } | 603 | } |
604 | 604 | ||
@@ -610,7 +610,7 @@ static int dm_flush_all(request_queue_t *q, struct gendisk *disk, | |||
610 | int ret = -ENXIO; | 610 | int ret = -ENXIO; |
611 | 611 | ||
612 | if (map) { | 612 | if (map) { |
613 | ret = dm_table_flush_all(md->map); | 613 | ret = dm_table_flush_all(map); |
614 | dm_table_put(map); | 614 | dm_table_put(map); |
615 | } | 615 | } |
616 | 616 | ||
@@ -747,7 +747,8 @@ static struct mapped_device *alloc_dev(unsigned int minor, int persistent) | |||
747 | goto bad1; | 747 | goto bad1; |
748 | 748 | ||
749 | memset(md, 0, sizeof(*md)); | 749 | memset(md, 0, sizeof(*md)); |
750 | init_rwsem(&md->lock); | 750 | init_rwsem(&md->io_lock); |
751 | init_MUTEX(&md->suspend_lock); | ||
751 | rwlock_init(&md->map_lock); | 752 | rwlock_init(&md->map_lock); |
752 | atomic_set(&md->holders, 1); | 753 | atomic_set(&md->holders, 1); |
753 | atomic_set(&md->event_nr, 0); | 754 | atomic_set(&md->event_nr, 0); |
@@ -825,18 +826,13 @@ static void event_callback(void *context) | |||
825 | wake_up(&md->eventq); | 826 | wake_up(&md->eventq); |
826 | } | 827 | } |
827 | 828 | ||
828 | static void __set_size(struct gendisk *disk, sector_t size) | 829 | static void __set_size(struct mapped_device *md, sector_t size) |
829 | { | 830 | { |
830 | struct block_device *bdev; | 831 | set_capacity(md->disk, size); |
831 | 832 | ||
832 | set_capacity(disk, size); | 833 | down(&md->frozen_bdev->bd_inode->i_sem); |
833 | bdev = bdget_disk(disk, 0); | 834 | i_size_write(md->frozen_bdev->bd_inode, (loff_t)size << SECTOR_SHIFT); |
834 | if (bdev) { | 835 | up(&md->frozen_bdev->bd_inode->i_sem); |
835 | down(&bdev->bd_inode->i_sem); | ||
836 | i_size_write(bdev->bd_inode, (loff_t)size << SECTOR_SHIFT); | ||
837 | up(&bdev->bd_inode->i_sem); | ||
838 | bdput(bdev); | ||
839 | } | ||
840 | } | 836 | } |
841 | 837 | ||
842 | static int __bind(struct mapped_device *md, struct dm_table *t) | 838 | static int __bind(struct mapped_device *md, struct dm_table *t) |
@@ -845,17 +841,18 @@ static int __bind(struct mapped_device *md, struct dm_table *t) | |||
845 | sector_t size; | 841 | sector_t size; |
846 | 842 | ||
847 | size = dm_table_get_size(t); | 843 | size = dm_table_get_size(t); |
848 | __set_size(md->disk, size); | 844 | __set_size(md, size); |
849 | if (size == 0) | 845 | if (size == 0) |
850 | return 0; | 846 | return 0; |
851 | 847 | ||
848 | dm_table_get(t); | ||
849 | dm_table_event_callback(t, event_callback, md); | ||
850 | |||
852 | write_lock(&md->map_lock); | 851 | write_lock(&md->map_lock); |
853 | md->map = t; | 852 | md->map = t; |
853 | dm_table_set_restrictions(t, q); | ||
854 | write_unlock(&md->map_lock); | 854 | write_unlock(&md->map_lock); |
855 | 855 | ||
856 | dm_table_get(t); | ||
857 | dm_table_event_callback(md->map, event_callback, md); | ||
858 | dm_table_set_restrictions(t, q); | ||
859 | return 0; | 856 | return 0; |
860 | } | 857 | } |
861 | 858 | ||
@@ -935,7 +932,7 @@ void dm_put(struct mapped_device *md) | |||
935 | struct dm_table *map = dm_get_table(md); | 932 | struct dm_table *map = dm_get_table(md); |
936 | 933 | ||
937 | if (atomic_dec_and_test(&md->holders)) { | 934 | if (atomic_dec_and_test(&md->holders)) { |
938 | if (!test_bit(DMF_SUSPENDED, &md->flags) && map) { | 935 | if (!dm_suspended(md)) { |
939 | dm_table_presuspend_targets(map); | 936 | dm_table_presuspend_targets(map); |
940 | dm_table_postsuspend_targets(map); | 937 | dm_table_postsuspend_targets(map); |
941 | } | 938 | } |
@@ -968,17 +965,17 @@ int dm_swap_table(struct mapped_device *md, struct dm_table *table) | |||
968 | { | 965 | { |
969 | int r = -EINVAL; | 966 | int r = -EINVAL; |
970 | 967 | ||
971 | down_write(&md->lock); | 968 | down(&md->suspend_lock); |
972 | 969 | ||
973 | /* device must be suspended */ | 970 | /* device must be suspended */ |
974 | if (!test_bit(DMF_SUSPENDED, &md->flags)) | 971 | if (!dm_suspended(md)) |
975 | goto out; | 972 | goto out; |
976 | 973 | ||
977 | __unbind(md); | 974 | __unbind(md); |
978 | r = __bind(md, table); | 975 | r = __bind(md, table); |
979 | 976 | ||
980 | out: | 977 | out: |
981 | up_write(&md->lock); | 978 | up(&md->suspend_lock); |
982 | return r; | 979 | return r; |
983 | } | 980 | } |
984 | 981 | ||
@@ -986,16 +983,13 @@ out: | |||
986 | * Functions to lock and unlock any filesystem running on the | 983 | * Functions to lock and unlock any filesystem running on the |
987 | * device. | 984 | * device. |
988 | */ | 985 | */ |
989 | static int __lock_fs(struct mapped_device *md) | 986 | static int lock_fs(struct mapped_device *md) |
990 | { | 987 | { |
991 | int error = -ENOMEM; | 988 | int r = -ENOMEM; |
992 | |||
993 | if (test_and_set_bit(DMF_FS_LOCKED, &md->flags)) | ||
994 | return 0; | ||
995 | 989 | ||
996 | md->frozen_bdev = bdget_disk(md->disk, 0); | 990 | md->frozen_bdev = bdget_disk(md->disk, 0); |
997 | if (!md->frozen_bdev) { | 991 | if (!md->frozen_bdev) { |
998 | DMWARN("bdget failed in __lock_fs"); | 992 | DMWARN("bdget failed in lock_fs"); |
999 | goto out; | 993 | goto out; |
1000 | } | 994 | } |
1001 | 995 | ||
@@ -1003,13 +997,13 @@ static int __lock_fs(struct mapped_device *md) | |||
1003 | 997 | ||
1004 | md->frozen_sb = freeze_bdev(md->frozen_bdev); | 998 | md->frozen_sb = freeze_bdev(md->frozen_bdev); |
1005 | if (IS_ERR(md->frozen_sb)) { | 999 | if (IS_ERR(md->frozen_sb)) { |
1006 | error = PTR_ERR(md->frozen_sb); | 1000 | r = PTR_ERR(md->frozen_sb); |
1007 | goto out_bdput; | 1001 | goto out_bdput; |
1008 | } | 1002 | } |
1009 | 1003 | ||
1010 | /* don't bdput right now, we don't want the bdev | 1004 | /* don't bdput right now, we don't want the bdev |
1011 | * to go away while it is locked. We'll bdput | 1005 | * to go away while it is locked. We'll bdput |
1012 | * in __unlock_fs | 1006 | * in unlock_fs |
1013 | */ | 1007 | */ |
1014 | return 0; | 1008 | return 0; |
1015 | 1009 | ||
@@ -1018,15 +1012,11 @@ out_bdput: | |||
1018 | md->frozen_sb = NULL; | 1012 | md->frozen_sb = NULL; |
1019 | md->frozen_bdev = NULL; | 1013 | md->frozen_bdev = NULL; |
1020 | out: | 1014 | out: |
1021 | clear_bit(DMF_FS_LOCKED, &md->flags); | 1015 | return r; |
1022 | return error; | ||
1023 | } | 1016 | } |
1024 | 1017 | ||
1025 | static void __unlock_fs(struct mapped_device *md) | 1018 | static void unlock_fs(struct mapped_device *md) |
1026 | { | 1019 | { |
1027 | if (!test_and_clear_bit(DMF_FS_LOCKED, &md->flags)) | ||
1028 | return; | ||
1029 | |||
1030 | thaw_bdev(md->frozen_bdev, md->frozen_sb); | 1020 | thaw_bdev(md->frozen_bdev, md->frozen_sb); |
1031 | bdput(md->frozen_bdev); | 1021 | bdput(md->frozen_bdev); |
1032 | 1022 | ||
@@ -1043,50 +1033,37 @@ static void __unlock_fs(struct mapped_device *md) | |||
1043 | */ | 1033 | */ |
1044 | int dm_suspend(struct mapped_device *md) | 1034 | int dm_suspend(struct mapped_device *md) |
1045 | { | 1035 | { |
1046 | struct dm_table *map; | 1036 | struct dm_table *map = NULL; |
1047 | DECLARE_WAITQUEUE(wait, current); | 1037 | DECLARE_WAITQUEUE(wait, current); |
1048 | int error = -EINVAL; | 1038 | int r = -EINVAL; |
1049 | 1039 | ||
1050 | /* Flush I/O to the device. */ | 1040 | down(&md->suspend_lock); |
1051 | down_read(&md->lock); | 1041 | |
1052 | if (test_bit(DMF_BLOCK_IO, &md->flags)) | 1042 | if (dm_suspended(md)) |
1053 | goto out_read_unlock; | 1043 | goto out; |
1054 | 1044 | ||
1055 | map = dm_get_table(md); | 1045 | map = dm_get_table(md); |
1056 | if (map) | ||
1057 | /* This does not get reverted if there's an error later. */ | ||
1058 | dm_table_presuspend_targets(map); | ||
1059 | 1046 | ||
1060 | error = __lock_fs(md); | 1047 | /* This does not get reverted if there's an error later. */ |
1061 | if (error) { | 1048 | dm_table_presuspend_targets(map); |
1062 | dm_table_put(map); | ||
1063 | goto out_read_unlock; | ||
1064 | } | ||
1065 | 1049 | ||
1066 | up_read(&md->lock); | 1050 | /* Flush I/O to the device. */ |
1051 | r = lock_fs(md); | ||
1052 | if (r) | ||
1053 | goto out; | ||
1067 | 1054 | ||
1068 | /* | 1055 | /* |
1069 | * First we set the BLOCK_IO flag so no more ios will be mapped. | 1056 | * First we set the BLOCK_IO flag so no more ios will be 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. | ||
1073 | */ | 1057 | */ |
1074 | error = -EINVAL; | 1058 | down_write(&md->io_lock); |
1075 | down_write(&md->lock); | 1059 | set_bit(DMF_BLOCK_IO, &md->flags); |
1076 | if (test_and_set_bit(DMF_BLOCK_IO, &md->flags)) { | ||
1077 | if (map) | ||
1078 | dm_table_put(map); | ||
1079 | goto out_write_unlock; | ||
1080 | } | ||
1081 | 1060 | ||
1082 | add_wait_queue(&md->wait, &wait); | 1061 | add_wait_queue(&md->wait, &wait); |
1083 | up_write(&md->lock); | 1062 | up_write(&md->io_lock); |
1084 | 1063 | ||
1085 | /* unplug */ | 1064 | /* unplug */ |
1086 | if (map) { | 1065 | if (map) |
1087 | dm_table_unplug_all(map); | 1066 | dm_table_unplug_all(map); |
1088 | dm_table_put(map); | ||
1089 | } | ||
1090 | 1067 | ||
1091 | /* | 1068 | /* |
1092 | * Then we wait for the already mapped ios to | 1069 | * Then we wait for the already mapped ios to |
@@ -1102,62 +1079,67 @@ int dm_suspend(struct mapped_device *md) | |||
1102 | } | 1079 | } |
1103 | set_current_state(TASK_RUNNING); | 1080 | set_current_state(TASK_RUNNING); |
1104 | 1081 | ||
1105 | down_write(&md->lock); | 1082 | down_write(&md->io_lock); |
1106 | remove_wait_queue(&md->wait, &wait); | 1083 | remove_wait_queue(&md->wait, &wait); |
1107 | 1084 | ||
1108 | /* were we interrupted ? */ | 1085 | /* were we interrupted ? */ |
1109 | error = -EINTR; | 1086 | r = -EINTR; |
1110 | if (atomic_read(&md->pending)) | 1087 | if (atomic_read(&md->pending)) { |
1111 | goto out_unfreeze; | 1088 | up_write(&md->io_lock); |
1112 | 1089 | unlock_fs(md); | |
1113 | set_bit(DMF_SUSPENDED, &md->flags); | 1090 | clear_bit(DMF_BLOCK_IO, &md->flags); |
1091 | goto out; | ||
1092 | } | ||
1093 | up_write(&md->io_lock); | ||
1114 | 1094 | ||
1115 | map = dm_get_table(md); | 1095 | dm_table_postsuspend_targets(map); |
1116 | if (map) | ||
1117 | dm_table_postsuspend_targets(map); | ||
1118 | dm_table_put(map); | ||
1119 | up_write(&md->lock); | ||
1120 | 1096 | ||
1121 | return 0; | 1097 | set_bit(DMF_SUSPENDED, &md->flags); |
1122 | 1098 | ||
1123 | out_unfreeze: | 1099 | r = 0; |
1124 | __unlock_fs(md); | ||
1125 | clear_bit(DMF_BLOCK_IO, &md->flags); | ||
1126 | out_write_unlock: | ||
1127 | up_write(&md->lock); | ||
1128 | return error; | ||
1129 | 1100 | ||
1130 | out_read_unlock: | 1101 | out: |
1131 | up_read(&md->lock); | 1102 | dm_table_put(map); |
1132 | return error; | 1103 | up(&md->suspend_lock); |
1104 | return r; | ||
1133 | } | 1105 | } |
1134 | 1106 | ||
1135 | int dm_resume(struct mapped_device *md) | 1107 | int dm_resume(struct mapped_device *md) |
1136 | { | 1108 | { |
1109 | int r = -EINVAL; | ||
1137 | struct bio *def; | 1110 | struct bio *def; |
1138 | struct dm_table *map = dm_get_table(md); | 1111 | struct dm_table *map = NULL; |
1139 | 1112 | ||
1140 | down_write(&md->lock); | 1113 | down(&md->suspend_lock); |
1141 | if (!map || | 1114 | if (!dm_suspended(md)) |
1142 | !test_bit(DMF_SUSPENDED, &md->flags) || | 1115 | goto out; |
1143 | !dm_table_get_size(map)) { | 1116 | |
1144 | up_write(&md->lock); | 1117 | map = dm_get_table(md); |
1145 | dm_table_put(map); | 1118 | if (!map || !dm_table_get_size(map)) |
1146 | return -EINVAL; | 1119 | goto out; |
1147 | } | ||
1148 | 1120 | ||
1149 | dm_table_resume_targets(map); | 1121 | dm_table_resume_targets(map); |
1150 | clear_bit(DMF_SUSPENDED, &md->flags); | 1122 | |
1123 | down_write(&md->io_lock); | ||
1151 | clear_bit(DMF_BLOCK_IO, &md->flags); | 1124 | clear_bit(DMF_BLOCK_IO, &md->flags); |
1152 | 1125 | ||
1153 | def = bio_list_get(&md->deferred); | 1126 | def = bio_list_get(&md->deferred); |
1154 | __flush_deferred_io(md, def); | 1127 | __flush_deferred_io(md, def); |
1155 | up_write(&md->lock); | 1128 | up_write(&md->io_lock); |
1156 | __unlock_fs(md); | 1129 | |
1130 | unlock_fs(md); | ||
1131 | |||
1132 | clear_bit(DMF_SUSPENDED, &md->flags); | ||
1133 | |||
1157 | dm_table_unplug_all(map); | 1134 | dm_table_unplug_all(map); |
1135 | |||
1136 | r = 0; | ||
1137 | |||
1138 | out: | ||
1158 | dm_table_put(map); | 1139 | dm_table_put(map); |
1140 | up(&md->suspend_lock); | ||
1159 | 1141 | ||
1160 | return 0; | 1142 | return r; |
1161 | } | 1143 | } |
1162 | 1144 | ||
1163 | /*----------------------------------------------------------------- | 1145 | /*----------------------------------------------------------------- |