diff options
Diffstat (limited to 'drivers/md/multipath.c')
-rw-r--r-- | drivers/md/multipath.c | 60 |
1 files changed, 32 insertions, 28 deletions
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index c35890990985..3535c23af288 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c | |||
@@ -146,7 +146,7 @@ static void multipath_status (struct seq_file *seq, mddev_t *mddev) | |||
146 | int i; | 146 | int i; |
147 | 147 | ||
148 | seq_printf (seq, " [%d/%d] [", conf->raid_disks, | 148 | seq_printf (seq, " [%d/%d] [", conf->raid_disks, |
149 | conf->working_disks); | 149 | conf->raid_disks - mddev->degraded); |
150 | for (i = 0; i < conf->raid_disks; i++) | 150 | for (i = 0; i < conf->raid_disks; i++) |
151 | seq_printf (seq, "%s", | 151 | seq_printf (seq, "%s", |
152 | conf->multipaths[i].rdev && | 152 | conf->multipaths[i].rdev && |
@@ -186,35 +186,36 @@ static int multipath_congested(void *data, int bits) | |||
186 | static void multipath_error (mddev_t *mddev, mdk_rdev_t *rdev) | 186 | static void multipath_error (mddev_t *mddev, mdk_rdev_t *rdev) |
187 | { | 187 | { |
188 | multipath_conf_t *conf = mddev->private; | 188 | multipath_conf_t *conf = mddev->private; |
189 | char b[BDEVNAME_SIZE]; | ||
189 | 190 | ||
190 | if (conf->working_disks <= 1) { | 191 | if (conf->raid_disks - mddev->degraded <= 1) { |
191 | /* | 192 | /* |
192 | * Uh oh, we can do nothing if this is our last path, but | 193 | * Uh oh, we can do nothing if this is our last path, but |
193 | * first check if this is a queued request for a device | 194 | * first check if this is a queued request for a device |
194 | * which has just failed. | 195 | * which has just failed. |
195 | */ | 196 | */ |
196 | printk(KERN_ALERT | 197 | printk(KERN_ALERT |
197 | "multipath: only one IO path left and IO error.\n"); | 198 | "multipath: only one IO path left and IO error.\n"); |
198 | /* leave it active... it's all we have */ | 199 | /* leave it active... it's all we have */ |
199 | } else { | 200 | return; |
200 | /* | 201 | } |
201 | * Mark disk as unusable | 202 | /* |
202 | */ | 203 | * Mark disk as unusable |
203 | if (!test_bit(Faulty, &rdev->flags)) { | 204 | */ |
204 | char b[BDEVNAME_SIZE]; | 205 | if (test_and_clear_bit(In_sync, &rdev->flags)) { |
205 | clear_bit(In_sync, &rdev->flags); | 206 | unsigned long flags; |
206 | set_bit(Faulty, &rdev->flags); | 207 | spin_lock_irqsave(&conf->device_lock, flags); |
207 | set_bit(MD_CHANGE_DEVS, &mddev->flags); | 208 | mddev->degraded++; |
208 | conf->working_disks--; | 209 | spin_unlock_irqrestore(&conf->device_lock, flags); |
209 | mddev->degraded++; | ||
210 | printk(KERN_ALERT "multipath: IO failure on %s," | ||
211 | " disabling IO path.\n" | ||
212 | "multipath: Operation continuing" | ||
213 | " on %d IO paths.\n", | ||
214 | bdevname (rdev->bdev,b), | ||
215 | conf->working_disks); | ||
216 | } | ||
217 | } | 210 | } |
211 | set_bit(Faulty, &rdev->flags); | ||
212 | set_bit(MD_CHANGE_DEVS, &mddev->flags); | ||
213 | printk(KERN_ALERT "multipath: IO failure on %s," | ||
214 | " disabling IO path.\n" | ||
215 | "multipath: Operation continuing" | ||
216 | " on %d IO paths.\n", | ||
217 | bdevname(rdev->bdev, b), | ||
218 | conf->raid_disks - mddev->degraded); | ||
218 | } | 219 | } |
219 | 220 | ||
220 | static void print_multipath_conf (multipath_conf_t *conf) | 221 | static void print_multipath_conf (multipath_conf_t *conf) |
@@ -227,7 +228,7 @@ static void print_multipath_conf (multipath_conf_t *conf) | |||
227 | printk("(conf==NULL)\n"); | 228 | printk("(conf==NULL)\n"); |
228 | return; | 229 | return; |
229 | } | 230 | } |
230 | printk(" --- wd:%d rd:%d\n", conf->working_disks, | 231 | printk(" --- wd:%d rd:%d\n", conf->raid_disks - conf->mddev->degraded, |
231 | conf->raid_disks); | 232 | conf->raid_disks); |
232 | 233 | ||
233 | for (i = 0; i < conf->raid_disks; i++) { | 234 | for (i = 0; i < conf->raid_disks; i++) { |
@@ -274,10 +275,11 @@ static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) | |||
274 | PAGE_CACHE_SIZE - 1); | 275 | PAGE_CACHE_SIZE - 1); |
275 | } | 276 | } |
276 | 277 | ||
277 | conf->working_disks++; | 278 | spin_lock_irq(&conf->device_lock); |
278 | mddev->degraded--; | 279 | mddev->degraded--; |
279 | rdev->raid_disk = path; | 280 | rdev->raid_disk = path; |
280 | set_bit(In_sync, &rdev->flags); | 281 | set_bit(In_sync, &rdev->flags); |
282 | spin_unlock_irq(&conf->device_lock); | ||
281 | rcu_assign_pointer(p->rdev, rdev); | 283 | rcu_assign_pointer(p->rdev, rdev); |
282 | err = 0; | 284 | err = 0; |
283 | md_integrity_add_rdev(rdev, mddev); | 285 | md_integrity_add_rdev(rdev, mddev); |
@@ -391,6 +393,7 @@ static int multipath_run (mddev_t *mddev) | |||
391 | int disk_idx; | 393 | int disk_idx; |
392 | struct multipath_info *disk; | 394 | struct multipath_info *disk; |
393 | mdk_rdev_t *rdev; | 395 | mdk_rdev_t *rdev; |
396 | int working_disks; | ||
394 | 397 | ||
395 | if (md_check_no_bitmap(mddev)) | 398 | if (md_check_no_bitmap(mddev)) |
396 | return -EINVAL; | 399 | return -EINVAL; |
@@ -424,7 +427,7 @@ static int multipath_run (mddev_t *mddev) | |||
424 | goto out_free_conf; | 427 | goto out_free_conf; |
425 | } | 428 | } |
426 | 429 | ||
427 | conf->working_disks = 0; | 430 | working_disks = 0; |
428 | list_for_each_entry(rdev, &mddev->disks, same_set) { | 431 | list_for_each_entry(rdev, &mddev->disks, same_set) { |
429 | disk_idx = rdev->raid_disk; | 432 | disk_idx = rdev->raid_disk; |
430 | if (disk_idx < 0 || | 433 | if (disk_idx < 0 || |
@@ -446,7 +449,7 @@ static int multipath_run (mddev_t *mddev) | |||
446 | } | 449 | } |
447 | 450 | ||
448 | if (!test_bit(Faulty, &rdev->flags)) | 451 | if (!test_bit(Faulty, &rdev->flags)) |
449 | conf->working_disks++; | 452 | working_disks++; |
450 | } | 453 | } |
451 | 454 | ||
452 | conf->raid_disks = mddev->raid_disks; | 455 | conf->raid_disks = mddev->raid_disks; |
@@ -454,12 +457,12 @@ static int multipath_run (mddev_t *mddev) | |||
454 | spin_lock_init(&conf->device_lock); | 457 | spin_lock_init(&conf->device_lock); |
455 | INIT_LIST_HEAD(&conf->retry_list); | 458 | INIT_LIST_HEAD(&conf->retry_list); |
456 | 459 | ||
457 | if (!conf->working_disks) { | 460 | if (!working_disks) { |
458 | printk(KERN_ERR "multipath: no operational IO paths for %s\n", | 461 | printk(KERN_ERR "multipath: no operational IO paths for %s\n", |
459 | mdname(mddev)); | 462 | mdname(mddev)); |
460 | goto out_free_conf; | 463 | goto out_free_conf; |
461 | } | 464 | } |
462 | mddev->degraded = conf->raid_disks - conf->working_disks; | 465 | mddev->degraded = conf->raid_disks - working_disks; |
463 | 466 | ||
464 | conf->pool = mempool_create_kmalloc_pool(NR_RESERVED_BUFS, | 467 | conf->pool = mempool_create_kmalloc_pool(NR_RESERVED_BUFS, |
465 | sizeof(struct multipath_bh)); | 468 | sizeof(struct multipath_bh)); |
@@ -481,7 +484,8 @@ static int multipath_run (mddev_t *mddev) | |||
481 | 484 | ||
482 | printk(KERN_INFO | 485 | printk(KERN_INFO |
483 | "multipath: array %s active with %d out of %d IO paths\n", | 486 | "multipath: array %s active with %d out of %d IO paths\n", |
484 | mdname(mddev), conf->working_disks, mddev->raid_disks); | 487 | mdname(mddev), conf->raid_disks - mddev->degraded, |
488 | mddev->raid_disks); | ||
485 | /* | 489 | /* |
486 | * Ok, everything is just fine now | 490 | * Ok, everything is just fine now |
487 | */ | 491 | */ |