diff options
Diffstat (limited to 'drivers/md/dm-mpath.c')
-rw-r--r-- | drivers/md/dm-mpath.c | 35 |
1 files changed, 25 insertions, 10 deletions
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 43763a0bd096..0c1b8520ef86 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c | |||
@@ -101,6 +101,7 @@ typedef int (*action_fn) (struct pgpath *pgpath); | |||
101 | 101 | ||
102 | static kmem_cache_t *_mpio_cache; | 102 | static kmem_cache_t *_mpio_cache; |
103 | 103 | ||
104 | struct workqueue_struct *kmultipathd; | ||
104 | static void process_queued_ios(void *data); | 105 | static void process_queued_ios(void *data); |
105 | static void trigger_event(void *data); | 106 | static void trigger_event(void *data); |
106 | 107 | ||
@@ -308,7 +309,7 @@ static int map_io(struct multipath *m, struct bio *bio, struct mpath_io *mpio, | |||
308 | bio_list_add(&m->queued_ios, bio); | 309 | bio_list_add(&m->queued_ios, bio); |
309 | m->queue_size++; | 310 | m->queue_size++; |
310 | if (m->pg_init_required || !m->queue_io) | 311 | if (m->pg_init_required || !m->queue_io) |
311 | schedule_work(&m->process_queued_ios); | 312 | queue_work(kmultipathd, &m->process_queued_ios); |
312 | pgpath = NULL; | 313 | pgpath = NULL; |
313 | r = 0; | 314 | r = 0; |
314 | } else if (!pgpath) | 315 | } else if (!pgpath) |
@@ -334,7 +335,7 @@ static int queue_if_no_path(struct multipath *m, unsigned queue_if_no_path) | |||
334 | 335 | ||
335 | m->queue_if_no_path = queue_if_no_path; | 336 | m->queue_if_no_path = queue_if_no_path; |
336 | if (!m->queue_if_no_path) | 337 | if (!m->queue_if_no_path) |
337 | schedule_work(&m->process_queued_ios); | 338 | queue_work(kmultipathd, &m->process_queued_ios); |
338 | 339 | ||
339 | spin_unlock_irqrestore(&m->lock, flags); | 340 | spin_unlock_irqrestore(&m->lock, flags); |
340 | 341 | ||
@@ -800,7 +801,7 @@ static int fail_path(struct pgpath *pgpath) | |||
800 | if (pgpath == m->current_pgpath) | 801 | if (pgpath == m->current_pgpath) |
801 | m->current_pgpath = NULL; | 802 | m->current_pgpath = NULL; |
802 | 803 | ||
803 | schedule_work(&m->trigger_event); | 804 | queue_work(kmultipathd, &m->trigger_event); |
804 | 805 | ||
805 | out: | 806 | out: |
806 | spin_unlock_irqrestore(&m->lock, flags); | 807 | spin_unlock_irqrestore(&m->lock, flags); |
@@ -837,9 +838,9 @@ static int reinstate_path(struct pgpath *pgpath) | |||
837 | 838 | ||
838 | m->current_pgpath = NULL; | 839 | m->current_pgpath = NULL; |
839 | if (!m->nr_valid_paths++) | 840 | if (!m->nr_valid_paths++) |
840 | schedule_work(&m->process_queued_ios); | 841 | queue_work(kmultipathd, &m->process_queued_ios); |
841 | 842 | ||
842 | schedule_work(&m->trigger_event); | 843 | queue_work(kmultipathd, &m->trigger_event); |
843 | 844 | ||
844 | out: | 845 | out: |
845 | spin_unlock_irqrestore(&m->lock, flags); | 846 | spin_unlock_irqrestore(&m->lock, flags); |
@@ -883,7 +884,7 @@ static void bypass_pg(struct multipath *m, struct priority_group *pg, | |||
883 | 884 | ||
884 | spin_unlock_irqrestore(&m->lock, flags); | 885 | spin_unlock_irqrestore(&m->lock, flags); |
885 | 886 | ||
886 | schedule_work(&m->trigger_event); | 887 | queue_work(kmultipathd, &m->trigger_event); |
887 | } | 888 | } |
888 | 889 | ||
889 | /* | 890 | /* |
@@ -913,7 +914,7 @@ static int switch_pg_num(struct multipath *m, const char *pgstr) | |||
913 | } | 914 | } |
914 | spin_unlock_irqrestore(&m->lock, flags); | 915 | spin_unlock_irqrestore(&m->lock, flags); |
915 | 916 | ||
916 | schedule_work(&m->trigger_event); | 917 | queue_work(kmultipathd, &m->trigger_event); |
917 | return 0; | 918 | return 0; |
918 | } | 919 | } |
919 | 920 | ||
@@ -968,7 +969,7 @@ void dm_pg_init_complete(struct path *path, unsigned err_flags) | |||
968 | m->current_pgpath = NULL; | 969 | m->current_pgpath = NULL; |
969 | m->current_pg = NULL; | 970 | m->current_pg = NULL; |
970 | } | 971 | } |
971 | schedule_work(&m->process_queued_ios); | 972 | queue_work(kmultipathd, &m->process_queued_ios); |
972 | spin_unlock_irqrestore(&m->lock, flags); | 973 | spin_unlock_irqrestore(&m->lock, flags); |
973 | } | 974 | } |
974 | 975 | ||
@@ -984,6 +985,9 @@ static int do_end_io(struct multipath *m, struct bio *bio, | |||
984 | if (!error) | 985 | if (!error) |
985 | return 0; /* I/O complete */ | 986 | return 0; /* I/O complete */ |
986 | 987 | ||
988 | if ((error == -EWOULDBLOCK) && bio_rw_ahead(bio)) | ||
989 | return error; | ||
990 | |||
987 | spin_lock(&m->lock); | 991 | spin_lock(&m->lock); |
988 | if (!m->nr_valid_paths) { | 992 | if (!m->nr_valid_paths) { |
989 | if (!m->queue_if_no_path || m->suspended) { | 993 | if (!m->queue_if_no_path || m->suspended) { |
@@ -1018,7 +1022,7 @@ static int do_end_io(struct multipath *m, struct bio *bio, | |||
1018 | bio_list_add(&m->queued_ios, bio); | 1022 | bio_list_add(&m->queued_ios, bio); |
1019 | m->queue_size++; | 1023 | m->queue_size++; |
1020 | if (!m->queue_io) | 1024 | if (!m->queue_io) |
1021 | schedule_work(&m->process_queued_ios); | 1025 | queue_work(kmultipathd, &m->process_queued_ios); |
1022 | spin_unlock(&m->lock); | 1026 | spin_unlock(&m->lock); |
1023 | 1027 | ||
1024 | return 1; /* io not complete */ | 1028 | return 1; /* io not complete */ |
@@ -1057,7 +1061,7 @@ static void multipath_presuspend(struct dm_target *ti) | |||
1057 | spin_lock_irqsave(&m->lock, flags); | 1061 | spin_lock_irqsave(&m->lock, flags); |
1058 | m->suspended = 1; | 1062 | m->suspended = 1; |
1059 | if (m->queue_if_no_path) | 1063 | if (m->queue_if_no_path) |
1060 | schedule_work(&m->process_queued_ios); | 1064 | queue_work(kmultipathd, &m->process_queued_ios); |
1061 | spin_unlock_irqrestore(&m->lock, flags); | 1065 | spin_unlock_irqrestore(&m->lock, flags); |
1062 | } | 1066 | } |
1063 | 1067 | ||
@@ -1274,6 +1278,15 @@ static int __init dm_multipath_init(void) | |||
1274 | return -EINVAL; | 1278 | return -EINVAL; |
1275 | } | 1279 | } |
1276 | 1280 | ||
1281 | kmultipathd = create_workqueue("kmpathd"); | ||
1282 | if (!kmultipathd) { | ||
1283 | DMERR("%s: failed to create workqueue kmpathd", | ||
1284 | multipath_target.name); | ||
1285 | dm_unregister_target(&multipath_target); | ||
1286 | kmem_cache_destroy(_mpio_cache); | ||
1287 | return -ENOMEM; | ||
1288 | } | ||
1289 | |||
1277 | DMINFO("dm-multipath version %u.%u.%u loaded", | 1290 | DMINFO("dm-multipath version %u.%u.%u loaded", |
1278 | multipath_target.version[0], multipath_target.version[1], | 1291 | multipath_target.version[0], multipath_target.version[1], |
1279 | multipath_target.version[2]); | 1292 | multipath_target.version[2]); |
@@ -1285,6 +1298,8 @@ static void __exit dm_multipath_exit(void) | |||
1285 | { | 1298 | { |
1286 | int r; | 1299 | int r; |
1287 | 1300 | ||
1301 | destroy_workqueue(kmultipathd); | ||
1302 | |||
1288 | r = dm_unregister_target(&multipath_target); | 1303 | r = dm_unregister_target(&multipath_target); |
1289 | if (r < 0) | 1304 | if (r < 0) |
1290 | DMERR("%s: target unregister failed %d", | 1305 | DMERR("%s: target unregister failed %d", |