diff options
Diffstat (limited to 'drivers/md/dm-mpath.c')
-rw-r--r-- | drivers/md/dm-mpath.c | 49 |
1 files changed, 42 insertions, 7 deletions
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 638dae048b4f..d8abb90a6c2f 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); |
@@ -1346,7 +1378,7 @@ static void multipath_resume(struct dm_target *ti) | |||
1346 | * num_paths num_selector_args [path_dev [selector_args]* ]+ ]+ | 1378 | * num_paths num_selector_args [path_dev [selector_args]* ]+ ]+ |
1347 | */ | 1379 | */ |
1348 | static int multipath_status(struct dm_target *ti, status_type_t type, | 1380 | static int multipath_status(struct dm_target *ti, status_type_t type, |
1349 | char *result, unsigned int maxlen) | 1381 | unsigned status_flags, char *result, unsigned maxlen) |
1350 | { | 1382 | { |
1351 | int sz = 0; | 1383 | int sz = 0; |
1352 | unsigned long flags; | 1384 | unsigned long flags; |
@@ -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, |