diff options
| -rw-r--r-- | drivers/md/dm-mpath.c | 47 |
1 files changed, 41 insertions, 6 deletions
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 638dae048b4f..8a3b2d53f81b 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c | |||
| @@ -85,6 +85,7 @@ struct multipath { | |||
| 85 | unsigned queue_io:1; /* Must we queue all I/O? */ | 85 | unsigned queue_io:1; /* Must we queue all I/O? */ |
| 86 | unsigned queue_if_no_path:1; /* Queue I/O if last path fails? */ | 86 | unsigned queue_if_no_path:1; /* Queue I/O if last path fails? */ |
| 87 | unsigned saved_queue_if_no_path:1; /* Saved state during suspension */ | 87 | unsigned saved_queue_if_no_path:1; /* Saved state during suspension */ |
| 88 | unsigned retain_attached_hw_handler:1; /* If there's already a hw_handler present, don't change it. */ | ||
| 88 | 89 | ||
| 89 | unsigned pg_init_retries; /* Number of times to retry pg_init */ | 90 | unsigned pg_init_retries; /* Number of times to retry pg_init */ |
| 90 | unsigned pg_init_count; /* Number of times pg_init called */ | 91 | unsigned pg_init_count; /* Number of times pg_init called */ |
| @@ -568,6 +569,8 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps | |||
| 568 | int r; | 569 | int r; |
| 569 | struct pgpath *p; | 570 | struct pgpath *p; |
| 570 | struct multipath *m = ti->private; | 571 | struct multipath *m = ti->private; |
| 572 | struct request_queue *q = NULL; | ||
| 573 | const char *attached_handler_name; | ||
| 571 | 574 | ||
| 572 | /* we need at least a path arg */ | 575 | /* we need at least a path arg */ |
| 573 | if (as->argc < 1) { | 576 | if (as->argc < 1) { |
| @@ -586,13 +589,37 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps | |||
| 586 | goto bad; | 589 | goto bad; |
| 587 | } | 590 | } |
| 588 | 591 | ||
| 589 | if (m->hw_handler_name) { | 592 | if (m->retain_attached_hw_handler || m->hw_handler_name) |
| 590 | struct request_queue *q = bdev_get_queue(p->path.dev->bdev); | 593 | q = bdev_get_queue(p->path.dev->bdev); |
| 594 | |||
| 595 | if (m->retain_attached_hw_handler) { | ||
| 596 | attached_handler_name = scsi_dh_attached_handler_name(q, GFP_KERNEL); | ||
| 597 | if (attached_handler_name) { | ||
| 598 | /* | ||
| 599 | * Reset hw_handler_name to match the attached handler | ||
| 600 | * and clear any hw_handler_params associated with the | ||
| 601 | * ignored handler. | ||
| 602 | * | ||
| 603 | * NB. This modifies the table line to show the actual | ||
| 604 | * handler instead of the original table passed in. | ||
| 605 | */ | ||
| 606 | kfree(m->hw_handler_name); | ||
| 607 | m->hw_handler_name = attached_handler_name; | ||
| 608 | |||
| 609 | kfree(m->hw_handler_params); | ||
| 610 | m->hw_handler_params = NULL; | ||
| 611 | } | ||
| 612 | } | ||
| 591 | 613 | ||
| 614 | if (m->hw_handler_name) { | ||
| 615 | /* | ||
| 616 | * Increments scsi_dh reference, even when using an | ||
| 617 | * already-attached handler. | ||
| 618 | */ | ||
| 592 | r = scsi_dh_attach(q, m->hw_handler_name); | 619 | r = scsi_dh_attach(q, m->hw_handler_name); |
| 593 | if (r == -EBUSY) { | 620 | if (r == -EBUSY) { |
| 594 | /* | 621 | /* |
| 595 | * Already attached to different hw_handler, | 622 | * Already attached to different hw_handler: |
| 596 | * try to reattach with correct one. | 623 | * try to reattach with correct one. |
| 597 | */ | 624 | */ |
| 598 | scsi_dh_detach(q); | 625 | scsi_dh_detach(q); |
| @@ -760,7 +787,7 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m) | |||
| 760 | const char *arg_name; | 787 | const char *arg_name; |
| 761 | 788 | ||
| 762 | static struct dm_arg _args[] = { | 789 | static struct dm_arg _args[] = { |
| 763 | {0, 5, "invalid number of feature args"}, | 790 | {0, 6, "invalid number of feature args"}, |
| 764 | {1, 50, "pg_init_retries must be between 1 and 50"}, | 791 | {1, 50, "pg_init_retries must be between 1 and 50"}, |
| 765 | {0, 60000, "pg_init_delay_msecs must be between 0 and 60000"}, | 792 | {0, 60000, "pg_init_delay_msecs must be between 0 and 60000"}, |
| 766 | }; | 793 | }; |
| @@ -781,6 +808,11 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m) | |||
| 781 | continue; | 808 | continue; |
| 782 | } | 809 | } |
| 783 | 810 | ||
| 811 | if (!strcasecmp(arg_name, "retain_attached_hw_handler")) { | ||
| 812 | m->retain_attached_hw_handler = 1; | ||
| 813 | continue; | ||
| 814 | } | ||
| 815 | |||
| 784 | if (!strcasecmp(arg_name, "pg_init_retries") && | 816 | if (!strcasecmp(arg_name, "pg_init_retries") && |
| 785 | (argc >= 1)) { | 817 | (argc >= 1)) { |
| 786 | r = dm_read_arg(_args + 1, as, &m->pg_init_retries, &ti->error); | 818 | r = dm_read_arg(_args + 1, as, &m->pg_init_retries, &ti->error); |
| @@ -1364,13 +1396,16 @@ static int multipath_status(struct dm_target *ti, status_type_t type, | |||
| 1364 | else { | 1396 | else { |
| 1365 | DMEMIT("%u ", m->queue_if_no_path + | 1397 | DMEMIT("%u ", m->queue_if_no_path + |
| 1366 | (m->pg_init_retries > 0) * 2 + | 1398 | (m->pg_init_retries > 0) * 2 + |
| 1367 | (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT) * 2); | 1399 | (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT) * 2 + |
| 1400 | m->retain_attached_hw_handler); | ||
| 1368 | if (m->queue_if_no_path) | 1401 | if (m->queue_if_no_path) |
| 1369 | DMEMIT("queue_if_no_path "); | 1402 | DMEMIT("queue_if_no_path "); |
| 1370 | if (m->pg_init_retries) | 1403 | if (m->pg_init_retries) |
| 1371 | DMEMIT("pg_init_retries %u ", m->pg_init_retries); | 1404 | DMEMIT("pg_init_retries %u ", m->pg_init_retries); |
| 1372 | if (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT) | 1405 | if (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT) |
| 1373 | DMEMIT("pg_init_delay_msecs %u ", m->pg_init_delay_msecs); | 1406 | DMEMIT("pg_init_delay_msecs %u ", m->pg_init_delay_msecs); |
| 1407 | if (m->retain_attached_hw_handler) | ||
| 1408 | DMEMIT("retain_attached_hw_handler "); | ||
| 1374 | } | 1409 | } |
| 1375 | 1410 | ||
| 1376 | if (!m->hw_handler_name || type == STATUSTYPE_INFO) | 1411 | if (!m->hw_handler_name || type == STATUSTYPE_INFO) |
| @@ -1656,7 +1691,7 @@ out: | |||
| 1656 | *---------------------------------------------------------------*/ | 1691 | *---------------------------------------------------------------*/ |
| 1657 | static struct target_type multipath_target = { | 1692 | static struct target_type multipath_target = { |
| 1658 | .name = "multipath", | 1693 | .name = "multipath", |
| 1659 | .version = {1, 4, 0}, | 1694 | .version = {1, 5, 0}, |
| 1660 | .module = THIS_MODULE, | 1695 | .module = THIS_MODULE, |
| 1661 | .ctr = multipath_ctr, | 1696 | .ctr = multipath_ctr, |
| 1662 | .dtr = multipath_dtr, | 1697 | .dtr = multipath_dtr, |
