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 | /*----------------------------------------------------------------- |
