diff options
author | Holger Smolinski <smolinski@de.ibm.com> | 2007-05-09 05:32:50 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-09 15:30:46 -0400 |
commit | 6ad36fe2b451cc85cc7b14f4128286759e217124 (patch) | |
tree | 05e6111d39c969ee729309d6bded6bcfe08aa44e /drivers/md | |
parent | 8defab33774a5c33920196a2ee9c0a946d22ba67 (diff) |
dm raid1: one kmirrord per mirror
This patch replaces the single instance of kmirrord by one instance per mirror
set. This change is required to avoid a deadlock in kmirrord when the
persistent dirty log of a mirror itself resides on a mirror. The single
instance of kmirrord then issues a sync write to the dirty log in write_bits
which gets deferred to kmirrord itself later in the call chain. But kmirrord
never does the deferred work because it is still waiting for the sync
write_bits.
_mirror_sets is removed as it no longer needed, and we always flush the
workqueue before destroying it to ensure all work is complete before
destroying it.
Signed-off-by: Holger Smolinski <smolinski@de.ibm.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Cc: Oleg Nesterov <oleg@tv-sign.ru>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/dm-raid1.c | 81 |
1 files changed, 27 insertions, 54 deletions
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 23a642619bed..c8b4c108da9e 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c | |||
@@ -22,15 +22,8 @@ | |||
22 | 22 | ||
23 | #define DM_MSG_PREFIX "raid1" | 23 | #define DM_MSG_PREFIX "raid1" |
24 | 24 | ||
25 | static struct workqueue_struct *_kmirrord_wq; | ||
26 | static struct work_struct _kmirrord_work; | ||
27 | static DECLARE_WAIT_QUEUE_HEAD(_kmirrord_recovery_stopped); | 25 | static DECLARE_WAIT_QUEUE_HEAD(_kmirrord_recovery_stopped); |
28 | 26 | ||
29 | static inline void wake(void) | ||
30 | { | ||
31 | queue_work(_kmirrord_wq, &_kmirrord_work); | ||
32 | } | ||
33 | |||
34 | /*----------------------------------------------------------------- | 27 | /*----------------------------------------------------------------- |
35 | * Region hash | 28 | * Region hash |
36 | * | 29 | * |
@@ -136,6 +129,9 @@ struct mirror_set { | |||
136 | 129 | ||
137 | struct mirror *default_mirror; /* Default mirror */ | 130 | struct mirror *default_mirror; /* Default mirror */ |
138 | 131 | ||
132 | struct workqueue_struct *kmirrord_wq; | ||
133 | struct work_struct kmirrord_work; | ||
134 | |||
139 | unsigned int nr_mirrors; | 135 | unsigned int nr_mirrors; |
140 | struct mirror mirror[0]; | 136 | struct mirror mirror[0]; |
141 | }; | 137 | }; |
@@ -153,6 +149,11 @@ static inline sector_t region_to_sector(struct region_hash *rh, region_t region) | |||
153 | return region << rh->region_shift; | 149 | return region << rh->region_shift; |
154 | } | 150 | } |
155 | 151 | ||
152 | static void wake(struct mirror_set *ms) | ||
153 | { | ||
154 | queue_work(ms->kmirrord_wq, &ms->kmirrord_work); | ||
155 | } | ||
156 | |||
156 | /* FIXME move this */ | 157 | /* FIXME move this */ |
157 | static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw); | 158 | static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw); |
158 | 159 | ||
@@ -471,7 +472,7 @@ static void rh_dec(struct region_hash *rh, region_t region) | |||
471 | spin_unlock_irqrestore(&rh->region_lock, flags); | 472 | spin_unlock_irqrestore(&rh->region_lock, flags); |
472 | 473 | ||
473 | if (should_wake) | 474 | if (should_wake) |
474 | wake(); | 475 | wake(rh->ms); |
475 | } | 476 | } |
476 | 477 | ||
477 | /* | 478 | /* |
@@ -558,7 +559,7 @@ static void rh_recovery_end(struct region *reg, int success) | |||
558 | list_add(®->list, ®->rh->recovered_regions); | 559 | list_add(®->list, ®->rh->recovered_regions); |
559 | spin_unlock_irq(&rh->region_lock); | 560 | spin_unlock_irq(&rh->region_lock); |
560 | 561 | ||
561 | wake(); | 562 | wake(rh->ms); |
562 | } | 563 | } |
563 | 564 | ||
564 | static void rh_flush(struct region_hash *rh) | 565 | static void rh_flush(struct region_hash *rh) |
@@ -592,7 +593,7 @@ static void rh_start_recovery(struct region_hash *rh) | |||
592 | for (i = 0; i < MAX_RECOVERY; i++) | 593 | for (i = 0; i < MAX_RECOVERY; i++) |
593 | up(&rh->recovery_count); | 594 | up(&rh->recovery_count); |
594 | 595 | ||
595 | wake(); | 596 | wake(rh->ms); |
596 | } | 597 | } |
597 | 598 | ||
598 | /* | 599 | /* |
@@ -870,11 +871,10 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes) | |||
870 | /*----------------------------------------------------------------- | 871 | /*----------------------------------------------------------------- |
871 | * kmirrord | 872 | * kmirrord |
872 | *---------------------------------------------------------------*/ | 873 | *---------------------------------------------------------------*/ |
873 | static LIST_HEAD(_mirror_sets); | 874 | static void do_mirror(struct work_struct *work) |
874 | static DECLARE_RWSEM(_mirror_sets_lock); | ||
875 | |||
876 | static void do_mirror(struct mirror_set *ms) | ||
877 | { | 875 | { |
876 | struct mirror_set *ms =container_of(work, struct mirror_set, | ||
877 | kmirrord_work); | ||
878 | struct bio_list reads, writes; | 878 | struct bio_list reads, writes; |
879 | 879 | ||
880 | spin_lock(&ms->lock); | 880 | spin_lock(&ms->lock); |
@@ -890,16 +890,6 @@ static void do_mirror(struct mirror_set *ms) | |||
890 | do_writes(ms, &writes); | 890 | do_writes(ms, &writes); |
891 | } | 891 | } |
892 | 892 | ||
893 | static void do_work(struct work_struct *ignored) | ||
894 | { | ||
895 | struct mirror_set *ms; | ||
896 | |||
897 | down_read(&_mirror_sets_lock); | ||
898 | list_for_each_entry (ms, &_mirror_sets, list) | ||
899 | do_mirror(ms); | ||
900 | up_read(&_mirror_sets_lock); | ||
901 | } | ||
902 | |||
903 | /*----------------------------------------------------------------- | 893 | /*----------------------------------------------------------------- |
904 | * Target functions | 894 | * Target functions |
905 | *---------------------------------------------------------------*/ | 895 | *---------------------------------------------------------------*/ |
@@ -978,23 +968,6 @@ static int get_mirror(struct mirror_set *ms, struct dm_target *ti, | |||
978 | return 0; | 968 | return 0; |
979 | } | 969 | } |
980 | 970 | ||
981 | static int add_mirror_set(struct mirror_set *ms) | ||
982 | { | ||
983 | down_write(&_mirror_sets_lock); | ||
984 | list_add_tail(&ms->list, &_mirror_sets); | ||
985 | up_write(&_mirror_sets_lock); | ||
986 | wake(); | ||
987 | |||
988 | return 0; | ||
989 | } | ||
990 | |||
991 | static void del_mirror_set(struct mirror_set *ms) | ||
992 | { | ||
993 | down_write(&_mirror_sets_lock); | ||
994 | list_del(&ms->list); | ||
995 | up_write(&_mirror_sets_lock); | ||
996 | } | ||
997 | |||
998 | /* | 971 | /* |
999 | * Create dirty log: log_type #log_params <log_params> | 972 | * Create dirty log: log_type #log_params <log_params> |
1000 | */ | 973 | */ |
@@ -1096,13 +1069,22 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
1096 | ti->private = ms; | 1069 | ti->private = ms; |
1097 | ti->split_io = ms->rh.region_size; | 1070 | ti->split_io = ms->rh.region_size; |
1098 | 1071 | ||
1072 | ms->kmirrord_wq = create_singlethread_workqueue("kmirrord"); | ||
1073 | if (!ms->kmirrord_wq) { | ||
1074 | DMERR("couldn't start kmirrord"); | ||
1075 | free_context(ms, ti, m); | ||
1076 | return -ENOMEM; | ||
1077 | } | ||
1078 | INIT_WORK(&ms->kmirrord_work, do_mirror); | ||
1079 | |||
1099 | r = kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client); | 1080 | r = kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client); |
1100 | if (r) { | 1081 | if (r) { |
1082 | destroy_workqueue(ms->kmirrord_wq); | ||
1101 | free_context(ms, ti, ms->nr_mirrors); | 1083 | free_context(ms, ti, ms->nr_mirrors); |
1102 | return r; | 1084 | return r; |
1103 | } | 1085 | } |
1104 | 1086 | ||
1105 | add_mirror_set(ms); | 1087 | wake(ms); |
1106 | return 0; | 1088 | return 0; |
1107 | } | 1089 | } |
1108 | 1090 | ||
@@ -1110,8 +1092,9 @@ static void mirror_dtr(struct dm_target *ti) | |||
1110 | { | 1092 | { |
1111 | struct mirror_set *ms = (struct mirror_set *) ti->private; | 1093 | struct mirror_set *ms = (struct mirror_set *) ti->private; |
1112 | 1094 | ||
1113 | del_mirror_set(ms); | 1095 | flush_workqueue(ms->kmirrord_wq); |
1114 | kcopyd_client_destroy(ms->kcopyd_client); | 1096 | kcopyd_client_destroy(ms->kcopyd_client); |
1097 | destroy_workqueue(ms->kmirrord_wq); | ||
1115 | free_context(ms, ti, ms->nr_mirrors); | 1098 | free_context(ms, ti, ms->nr_mirrors); |
1116 | } | 1099 | } |
1117 | 1100 | ||
@@ -1127,7 +1110,7 @@ static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw) | |||
1127 | spin_unlock(&ms->lock); | 1110 | spin_unlock(&ms->lock); |
1128 | 1111 | ||
1129 | if (should_wake) | 1112 | if (should_wake) |
1130 | wake(); | 1113 | wake(ms); |
1131 | } | 1114 | } |
1132 | 1115 | ||
1133 | /* | 1116 | /* |
@@ -1270,20 +1253,11 @@ static int __init dm_mirror_init(void) | |||
1270 | if (r) | 1253 | if (r) |
1271 | return r; | 1254 | return r; |
1272 | 1255 | ||
1273 | _kmirrord_wq = create_singlethread_workqueue("kmirrord"); | ||
1274 | if (!_kmirrord_wq) { | ||
1275 | DMERR("couldn't start kmirrord"); | ||
1276 | dm_dirty_log_exit(); | ||
1277 | return r; | ||
1278 | } | ||
1279 | INIT_WORK(&_kmirrord_work, do_work); | ||
1280 | |||
1281 | r = dm_register_target(&mirror_target); | 1256 | r = dm_register_target(&mirror_target); |
1282 | if (r < 0) { | 1257 | if (r < 0) { |
1283 | DMERR("%s: Failed to register mirror target", | 1258 | DMERR("%s: Failed to register mirror target", |
1284 | mirror_target.name); | 1259 | mirror_target.name); |
1285 | dm_dirty_log_exit(); | 1260 | dm_dirty_log_exit(); |
1286 | destroy_workqueue(_kmirrord_wq); | ||
1287 | } | 1261 | } |
1288 | 1262 | ||
1289 | return r; | 1263 | return r; |
@@ -1297,7 +1271,6 @@ static void __exit dm_mirror_exit(void) | |||
1297 | if (r < 0) | 1271 | if (r < 0) |
1298 | DMERR("%s: unregister failed %d", mirror_target.name, r); | 1272 | DMERR("%s: unregister failed %d", mirror_target.name, r); |
1299 | 1273 | ||
1300 | destroy_workqueue(_kmirrord_wq); | ||
1301 | dm_dirty_log_exit(); | 1274 | dm_dirty_log_exit(); |
1302 | } | 1275 | } |
1303 | 1276 | ||