diff options
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/dm-mpath.c | 37 |
1 files changed, 23 insertions, 14 deletions
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 98da8eee2d2c..785806bdb248 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -63,6 +63,7 @@ struct multipath { unsigned nr_priority_groups; struct list_head priority_groups; unsigned pg_init_required; /* pg_init needs calling? */ + unsigned pg_init_in_progress; /* Only one pg_init allowed at once */ unsigned nr_valid_paths; /* Total number of usable paths */ struct pgpath *current_pgpath; @@ -308,7 +309,8 @@ static int map_io(struct multipath *m, struct bio *bio, struct mpath_io *mpio, /* Queue for the daemon to resubmit */ bio_list_add(&m->queued_ios, bio); m->queue_size++; - if (m->pg_init_required || !m->queue_io) + if ((m->pg_init_required && !m->pg_init_in_progress) || + !m->queue_io) queue_work(kmultipathd, &m->process_queued_ios); pgpath = NULL; r = 0; @@ -335,7 +337,7 @@ static int queue_if_no_path(struct multipath *m, unsigned queue_if_no_path) m->saved_queue_if_no_path = m->queue_if_no_path; m->queue_if_no_path = queue_if_no_path; - if (!m->queue_if_no_path) + if (!m->queue_if_no_path && m->queue_size) queue_work(kmultipathd, &m->process_queued_ios); spin_unlock_irqrestore(&m->lock, flags); @@ -380,25 +382,31 @@ static void process_queued_ios(void *data) { struct multipath *m = (struct multipath *) data; struct hw_handler *hwh = &m->hw_handler; - struct pgpath *pgpath; - unsigned init_required, must_queue = 0; + struct pgpath *pgpath = NULL; + unsigned init_required = 0, must_queue = 1; unsigned long flags; spin_lock_irqsave(&m->lock, flags); + if (!m->queue_size) + goto out; + if (!m->current_pgpath) __choose_pgpath(m); pgpath = m->current_pgpath; - if ((pgpath && m->queue_io) || - (!pgpath && m->queue_if_no_path)) - must_queue = 1; + if ((pgpath && !m->queue_io) || + (!pgpath && !m->queue_if_no_path)) + must_queue = 0; - init_required = m->pg_init_required; - if (init_required) + if (m->pg_init_required && !m->pg_init_in_progress) { m->pg_init_required = 0; + m->pg_init_in_progress = 1; + init_required = 1; + } +out: spin_unlock_irqrestore(&m->lock, flags); if (init_required) @@ -843,7 +851,7 @@ static int reinstate_path(struct pgpath *pgpath) pgpath->path.is_active = 1; m->current_pgpath = NULL; - if (!m->nr_valid_paths++) + if (!m->nr_valid_paths++ && m->queue_size) queue_work(kmultipathd, &m->process_queued_ios); queue_work(kmultipathd, &m->trigger_event); @@ -969,12 +977,13 @@ void dm_pg_init_complete(struct path *path, unsigned err_flags) bypass_pg(m, pg, 1); spin_lock_irqsave(&m->lock, flags); - if (!err_flags) - m->queue_io = 0; - else { + if (err_flags) { m->current_pgpath = NULL; m->current_pg = NULL; - } + } else if (!m->pg_init_required) + m->queue_io = 0; + + m->pg_init_in_progress = 0; queue_work(kmultipathd, &m->process_queued_ios); spin_unlock_irqrestore(&m->lock, flags); } |