diff options
Diffstat (limited to 'drivers/md/dm-raid1.c')
-rw-r--r-- | drivers/md/dm-raid1.c | 35 |
1 files changed, 20 insertions, 15 deletions
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index d09ff15490a5..31123d4a6b9c 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/time.h> | 19 | #include <linux/time.h> |
20 | #include <linux/vmalloc.h> | 20 | #include <linux/vmalloc.h> |
21 | #include <linux/workqueue.h> | 21 | #include <linux/workqueue.h> |
22 | #include <linux/log2.h> | ||
22 | 23 | ||
23 | #define DM_MSG_PREFIX "raid1" | 24 | #define DM_MSG_PREFIX "raid1" |
24 | #define DM_IO_PAGES 64 | 25 | #define DM_IO_PAGES 64 |
@@ -113,6 +114,7 @@ struct region { | |||
113 | * Mirror set structures. | 114 | * Mirror set structures. |
114 | *---------------------------------------------------------------*/ | 115 | *---------------------------------------------------------------*/ |
115 | struct mirror { | 116 | struct mirror { |
117 | struct mirror_set *ms; | ||
116 | atomic_t error_count; | 118 | atomic_t error_count; |
117 | struct dm_dev *dev; | 119 | struct dm_dev *dev; |
118 | sector_t offset; | 120 | sector_t offset; |
@@ -974,6 +976,7 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors, | |||
974 | 976 | ||
975 | if (rh_init(&ms->rh, ms, dl, region_size, ms->nr_regions)) { | 977 | if (rh_init(&ms->rh, ms, dl, region_size, ms->nr_regions)) { |
976 | ti->error = "Error creating dirty region hash"; | 978 | ti->error = "Error creating dirty region hash"; |
979 | dm_io_client_destroy(ms->io_client); | ||
977 | kfree(ms); | 980 | kfree(ms); |
978 | return NULL; | 981 | return NULL; |
979 | } | 982 | } |
@@ -994,7 +997,7 @@ static void free_context(struct mirror_set *ms, struct dm_target *ti, | |||
994 | 997 | ||
995 | static inline int _check_region_size(struct dm_target *ti, uint32_t size) | 998 | static inline int _check_region_size(struct dm_target *ti, uint32_t size) |
996 | { | 999 | { |
997 | return !(size % (PAGE_SIZE >> 9) || (size & (size - 1)) || | 1000 | return !(size % (PAGE_SIZE >> 9) || !is_power_of_2(size) || |
998 | size > ti->len); | 1001 | size > ti->len); |
999 | } | 1002 | } |
1000 | 1003 | ||
@@ -1015,6 +1018,7 @@ static int get_mirror(struct mirror_set *ms, struct dm_target *ti, | |||
1015 | return -ENXIO; | 1018 | return -ENXIO; |
1016 | } | 1019 | } |
1017 | 1020 | ||
1021 | ms->mirror[mirror].ms = ms; | ||
1018 | ms->mirror[mirror].offset = offset; | 1022 | ms->mirror[mirror].offset = offset; |
1019 | 1023 | ||
1020 | return 0; | 1024 | return 0; |
@@ -1163,16 +1167,14 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
1163 | ms->kmirrord_wq = create_singlethread_workqueue("kmirrord"); | 1167 | ms->kmirrord_wq = create_singlethread_workqueue("kmirrord"); |
1164 | if (!ms->kmirrord_wq) { | 1168 | if (!ms->kmirrord_wq) { |
1165 | DMERR("couldn't start kmirrord"); | 1169 | DMERR("couldn't start kmirrord"); |
1166 | free_context(ms, ti, m); | 1170 | r = -ENOMEM; |
1167 | return -ENOMEM; | 1171 | goto err_free_context; |
1168 | } | 1172 | } |
1169 | INIT_WORK(&ms->kmirrord_work, do_mirror); | 1173 | INIT_WORK(&ms->kmirrord_work, do_mirror); |
1170 | 1174 | ||
1171 | r = parse_features(ms, argc, argv, &args_used); | 1175 | r = parse_features(ms, argc, argv, &args_used); |
1172 | if (r) { | 1176 | if (r) |
1173 | free_context(ms, ti, ms->nr_mirrors); | 1177 | goto err_destroy_wq; |
1174 | return r; | ||
1175 | } | ||
1176 | 1178 | ||
1177 | argv += args_used; | 1179 | argv += args_used; |
1178 | argc -= args_used; | 1180 | argc -= args_used; |
@@ -1188,19 +1190,22 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
1188 | 1190 | ||
1189 | if (argc) { | 1191 | if (argc) { |
1190 | ti->error = "Too many mirror arguments"; | 1192 | ti->error = "Too many mirror arguments"; |
1191 | free_context(ms, ti, ms->nr_mirrors); | 1193 | r = -EINVAL; |
1192 | return -EINVAL; | 1194 | goto err_destroy_wq; |
1193 | } | 1195 | } |
1194 | 1196 | ||
1195 | r = kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client); | 1197 | r = kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client); |
1196 | if (r) { | 1198 | if (r) |
1197 | destroy_workqueue(ms->kmirrord_wq); | 1199 | goto err_destroy_wq; |
1198 | free_context(ms, ti, ms->nr_mirrors); | ||
1199 | return r; | ||
1200 | } | ||
1201 | 1200 | ||
1202 | wake(ms); | 1201 | wake(ms); |
1203 | return 0; | 1202 | return 0; |
1203 | |||
1204 | err_destroy_wq: | ||
1205 | destroy_workqueue(ms->kmirrord_wq); | ||
1206 | err_free_context: | ||
1207 | free_context(ms, ti, ms->nr_mirrors); | ||
1208 | return r; | ||
1204 | } | 1209 | } |
1205 | 1210 | ||
1206 | static void mirror_dtr(struct dm_target *ti) | 1211 | static void mirror_dtr(struct dm_target *ti) |
@@ -1302,7 +1307,7 @@ static void mirror_postsuspend(struct dm_target *ti) | |||
1302 | wait_event(_kmirrord_recovery_stopped, | 1307 | wait_event(_kmirrord_recovery_stopped, |
1303 | !atomic_read(&ms->rh.recovery_in_flight)); | 1308 | !atomic_read(&ms->rh.recovery_in_flight)); |
1304 | 1309 | ||
1305 | if (log->type->suspend && log->type->suspend(log)) | 1310 | if (log->type->postsuspend && log->type->postsuspend(log)) |
1306 | /* FIXME: need better error handling */ | 1311 | /* FIXME: need better error handling */ |
1307 | DMWARN("log suspend failed"); | 1312 | DMWARN("log suspend failed"); |
1308 | } | 1313 | } |