diff options
Diffstat (limited to 'drivers/md/dm-mpath.c')
| -rw-r--r-- | drivers/md/dm-mpath.c | 16 | 
1 files changed, 15 insertions, 1 deletions
| diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 71dd65aa31b6..c2fcf28b4c70 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c | |||
| @@ -63,6 +63,7 @@ struct multipath { | |||
| 63 | 63 | ||
| 64 | const char *hw_handler_name; | 64 | const char *hw_handler_name; | 
| 65 | struct work_struct activate_path; | 65 | struct work_struct activate_path; | 
| 66 | struct pgpath *pgpath_to_activate; | ||
| 66 | unsigned nr_priority_groups; | 67 | unsigned nr_priority_groups; | 
| 67 | struct list_head priority_groups; | 68 | struct list_head priority_groups; | 
| 68 | unsigned pg_init_required; /* pg_init needs calling? */ | 69 | unsigned pg_init_required; /* pg_init needs calling? */ | 
| @@ -146,6 +147,7 @@ static struct priority_group *alloc_priority_group(void) | |||
| 146 | 147 | ||
| 147 | static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti) | 148 | static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti) | 
| 148 | { | 149 | { | 
| 150 | unsigned long flags; | ||
| 149 | struct pgpath *pgpath, *tmp; | 151 | struct pgpath *pgpath, *tmp; | 
| 150 | struct multipath *m = ti->private; | 152 | struct multipath *m = ti->private; | 
| 151 | 153 | ||
| @@ -154,6 +156,10 @@ static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti) | |||
| 154 | if (m->hw_handler_name) | 156 | if (m->hw_handler_name) | 
| 155 | scsi_dh_detach(bdev_get_queue(pgpath->path.dev->bdev)); | 157 | scsi_dh_detach(bdev_get_queue(pgpath->path.dev->bdev)); | 
| 156 | dm_put_device(ti, pgpath->path.dev); | 158 | dm_put_device(ti, pgpath->path.dev); | 
| 159 | spin_lock_irqsave(&m->lock, flags); | ||
| 160 | if (m->pgpath_to_activate == pgpath) | ||
| 161 | m->pgpath_to_activate = NULL; | ||
| 162 | spin_unlock_irqrestore(&m->lock, flags); | ||
| 157 | free_pgpath(pgpath); | 163 | free_pgpath(pgpath); | 
| 158 | } | 164 | } | 
| 159 | } | 165 | } | 
| @@ -421,6 +427,7 @@ static void process_queued_ios(struct work_struct *work) | |||
| 421 | __choose_pgpath(m); | 427 | __choose_pgpath(m); | 
| 422 | 428 | ||
| 423 | pgpath = m->current_pgpath; | 429 | pgpath = m->current_pgpath; | 
| 430 | m->pgpath_to_activate = m->current_pgpath; | ||
| 424 | 431 | ||
| 425 | if ((pgpath && !m->queue_io) || | 432 | if ((pgpath && !m->queue_io) || | 
| 426 | (!pgpath && !m->queue_if_no_path)) | 433 | (!pgpath && !m->queue_if_no_path)) | 
| @@ -1093,8 +1100,15 @@ static void activate_path(struct work_struct *work) | |||
| 1093 | int ret; | 1100 | int ret; | 
| 1094 | struct multipath *m = | 1101 | struct multipath *m = | 
| 1095 | container_of(work, struct multipath, activate_path); | 1102 | container_of(work, struct multipath, activate_path); | 
| 1096 | struct dm_path *path = &m->current_pgpath->path; | 1103 | struct dm_path *path; | 
| 1104 | unsigned long flags; | ||
| 1097 | 1105 | ||
| 1106 | spin_lock_irqsave(&m->lock, flags); | ||
| 1107 | path = &m->pgpath_to_activate->path; | ||
| 1108 | m->pgpath_to_activate = NULL; | ||
| 1109 | spin_unlock_irqrestore(&m->lock, flags); | ||
| 1110 | if (!path) | ||
| 1111 | return; | ||
| 1098 | ret = scsi_dh_activate(bdev_get_queue(path->dev->bdev)); | 1112 | ret = scsi_dh_activate(bdev_get_queue(path->dev->bdev)); | 
| 1099 | pg_init_done(path, ret); | 1113 | pg_init_done(path, ret); | 
| 1100 | } | 1114 | } | 
