diff options
author | Chandra Seetharaman <sekharan@us.ibm.com> | 2011-01-13 15:00:01 -0500 |
---|---|---|
committer | Alasdair G Kergon <agk@redhat.com> | 2011-01-13 15:00:01 -0500 |
commit | 4e2d19e46b507018c6ed15f6c081d8f887ae229c (patch) | |
tree | c4004056ca62763c87e5dae1c19d7e22877ec571 | |
parent | 052189a2ec956810feefb6a681416c5e6a207646 (diff) |
dm mpath: delay activate_path retry on SCSI_DH_RETRY
This patch adds a user-configurable 'pg_init_delay_msecs' feature. Use
this feature to specify the number of milliseconds to delay before
retrying scsi_dh_activate, when SCSI_DH_RETRY is returned.
SCSI Device Handlers return SCSI_DH_IMM_RETRY if we could retry
activation immediately and SCSI_DH_RETRY in cases where it is better to
retry after some delay.
Currently we immediately retry scsi_dh_activate irrespective of
SCSI_DH_IMM_RETRY and SCSI_DH_RETRY.
The 'pg_init_delay_msecs' feature may be provided during table create or
load, e.g.:
dmsetup create --table "0 20971520 multipath 3 queue_if_no_path \
pg_init_delay_msecs 2500 ..." mpatha
The default for 'pg_init_delay_msecs' is 2000 milliseconds.
Maximum configurable delay is 60000 milliseconds. Specifying a
'pg_init_delay_msecs' of 0 will cause immediate retry.
Signed-off-by: Nikanth Karthikesan <knikanth@suse.de>
Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
Acked-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
-rw-r--r-- | drivers/md/dm-mpath.c | 48 |
1 files changed, 38 insertions, 10 deletions
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 35ab5781f88f..b82d28819e2a 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c | |||
@@ -23,6 +23,8 @@ | |||
23 | 23 | ||
24 | #define DM_MSG_PREFIX "multipath" | 24 | #define DM_MSG_PREFIX "multipath" |
25 | #define MESG_STR(x) x, sizeof(x) | 25 | #define MESG_STR(x) x, sizeof(x) |
26 | #define DM_PG_INIT_DELAY_MSECS 2000 | ||
27 | #define DM_PG_INIT_DELAY_DEFAULT ((unsigned) -1) | ||
26 | 28 | ||
27 | /* Path properties */ | 29 | /* Path properties */ |
28 | struct pgpath { | 30 | struct pgpath { |
@@ -33,7 +35,7 @@ struct pgpath { | |||
33 | unsigned fail_count; /* Cumulative failure count */ | 35 | unsigned fail_count; /* Cumulative failure count */ |
34 | 36 | ||
35 | struct dm_path path; | 37 | struct dm_path path; |
36 | struct work_struct activate_path; | 38 | struct delayed_work activate_path; |
37 | }; | 39 | }; |
38 | 40 | ||
39 | #define path_to_pgpath(__pgp) container_of((__pgp), struct pgpath, path) | 41 | #define path_to_pgpath(__pgp) container_of((__pgp), struct pgpath, path) |
@@ -64,11 +66,15 @@ struct multipath { | |||
64 | 66 | ||
65 | const char *hw_handler_name; | 67 | const char *hw_handler_name; |
66 | char *hw_handler_params; | 68 | char *hw_handler_params; |
69 | |||
67 | unsigned nr_priority_groups; | 70 | unsigned nr_priority_groups; |
68 | struct list_head priority_groups; | 71 | struct list_head priority_groups; |
72 | |||
73 | wait_queue_head_t pg_init_wait; /* Wait for pg_init completion */ | ||
74 | |||
69 | unsigned pg_init_required; /* pg_init needs calling? */ | 75 | unsigned pg_init_required; /* pg_init needs calling? */ |
70 | unsigned pg_init_in_progress; /* Only one pg_init allowed at once */ | 76 | unsigned pg_init_in_progress; /* Only one pg_init allowed at once */ |
71 | wait_queue_head_t pg_init_wait; /* Wait for pg_init completion */ | 77 | unsigned pg_init_delay_retry; /* Delay pg_init retry? */ |
72 | 78 | ||
73 | unsigned nr_valid_paths; /* Total number of usable paths */ | 79 | unsigned nr_valid_paths; /* Total number of usable paths */ |
74 | struct pgpath *current_pgpath; | 80 | struct pgpath *current_pgpath; |
@@ -81,6 +87,7 @@ struct multipath { | |||
81 | unsigned saved_queue_if_no_path;/* Saved state during suspension */ | 87 | unsigned saved_queue_if_no_path;/* Saved state during suspension */ |
82 | unsigned pg_init_retries; /* Number of times to retry pg_init */ | 88 | unsigned pg_init_retries; /* Number of times to retry pg_init */ |
83 | unsigned pg_init_count; /* Number of times pg_init called */ | 89 | unsigned pg_init_count; /* Number of times pg_init called */ |
90 | unsigned pg_init_delay_msecs; /* Number of msecs before pg_init retry */ | ||
84 | 91 | ||
85 | struct work_struct process_queued_ios; | 92 | struct work_struct process_queued_ios; |
86 | struct list_head queued_ios; | 93 | struct list_head queued_ios; |
@@ -127,7 +134,7 @@ static struct pgpath *alloc_pgpath(void) | |||
127 | 134 | ||
128 | if (pgpath) { | 135 | if (pgpath) { |
129 | pgpath->is_active = 1; | 136 | pgpath->is_active = 1; |
130 | INIT_WORK(&pgpath->activate_path, activate_path); | 137 | INIT_DELAYED_WORK(&pgpath->activate_path, activate_path); |
131 | } | 138 | } |
132 | 139 | ||
133 | return pgpath; | 140 | return pgpath; |
@@ -188,6 +195,7 @@ static struct multipath *alloc_multipath(struct dm_target *ti) | |||
188 | INIT_LIST_HEAD(&m->queued_ios); | 195 | INIT_LIST_HEAD(&m->queued_ios); |
189 | spin_lock_init(&m->lock); | 196 | spin_lock_init(&m->lock); |
190 | m->queue_io = 1; | 197 | m->queue_io = 1; |
198 | m->pg_init_delay_msecs = DM_PG_INIT_DELAY_DEFAULT; | ||
191 | INIT_WORK(&m->process_queued_ios, process_queued_ios); | 199 | INIT_WORK(&m->process_queued_ios, process_queued_ios); |
192 | INIT_WORK(&m->trigger_event, trigger_event); | 200 | INIT_WORK(&m->trigger_event, trigger_event); |
193 | init_waitqueue_head(&m->pg_init_wait); | 201 | init_waitqueue_head(&m->pg_init_wait); |
@@ -227,14 +235,19 @@ static void free_multipath(struct multipath *m) | |||
227 | static void __pg_init_all_paths(struct multipath *m) | 235 | static void __pg_init_all_paths(struct multipath *m) |
228 | { | 236 | { |
229 | struct pgpath *pgpath; | 237 | struct pgpath *pgpath; |
238 | unsigned long pg_init_delay = 0; | ||
230 | 239 | ||
231 | m->pg_init_count++; | 240 | m->pg_init_count++; |
232 | m->pg_init_required = 0; | 241 | m->pg_init_required = 0; |
242 | if (m->pg_init_delay_retry) | ||
243 | pg_init_delay = msecs_to_jiffies(m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT ? | ||
244 | m->pg_init_delay_msecs : DM_PG_INIT_DELAY_MSECS); | ||
233 | list_for_each_entry(pgpath, &m->current_pg->pgpaths, list) { | 245 | list_for_each_entry(pgpath, &m->current_pg->pgpaths, list) { |
234 | /* Skip failed paths */ | 246 | /* Skip failed paths */ |
235 | if (!pgpath->is_active) | 247 | if (!pgpath->is_active) |
236 | continue; | 248 | continue; |
237 | if (queue_work(kmpath_handlerd, &pgpath->activate_path)) | 249 | if (queue_delayed_work(kmpath_handlerd, &pgpath->activate_path, |
250 | pg_init_delay)) | ||
238 | m->pg_init_in_progress++; | 251 | m->pg_init_in_progress++; |
239 | } | 252 | } |
240 | } | 253 | } |
@@ -782,8 +795,9 @@ static int parse_features(struct arg_set *as, struct multipath *m) | |||
782 | const char *param_name; | 795 | const char *param_name; |
783 | 796 | ||
784 | static struct param _params[] = { | 797 | static struct param _params[] = { |
785 | {0, 3, "invalid number of feature args"}, | 798 | {0, 5, "invalid number of feature args"}, |
786 | {1, 50, "pg_init_retries must be between 1 and 50"}, | 799 | {1, 50, "pg_init_retries must be between 1 and 50"}, |
800 | {0, 60000, "pg_init_delay_msecs must be between 0 and 60000"}, | ||
787 | }; | 801 | }; |
788 | 802 | ||
789 | r = read_param(_params, shift(as), &argc, &ti->error); | 803 | r = read_param(_params, shift(as), &argc, &ti->error); |
@@ -810,6 +824,14 @@ static int parse_features(struct arg_set *as, struct multipath *m) | |||
810 | continue; | 824 | continue; |
811 | } | 825 | } |
812 | 826 | ||
827 | if (!strnicmp(param_name, MESG_STR("pg_init_delay_msecs")) && | ||
828 | (argc >= 1)) { | ||
829 | r = read_param(_params + 2, shift(as), | ||
830 | &m->pg_init_delay_msecs, &ti->error); | ||
831 | argc--; | ||
832 | continue; | ||
833 | } | ||
834 | |||
813 | ti->error = "Unrecognised multipath feature request"; | 835 | ti->error = "Unrecognised multipath feature request"; |
814 | r = -EINVAL; | 836 | r = -EINVAL; |
815 | } while (argc && !r); | 837 | } while (argc && !r); |
@@ -1022,7 +1044,7 @@ static int reinstate_path(struct pgpath *pgpath) | |||
1022 | m->current_pgpath = NULL; | 1044 | m->current_pgpath = NULL; |
1023 | queue_work(kmultipathd, &m->process_queued_ios); | 1045 | queue_work(kmultipathd, &m->process_queued_ios); |
1024 | } else if (m->hw_handler_name && (m->current_pg == pgpath->pg)) { | 1046 | } else if (m->hw_handler_name && (m->current_pg == pgpath->pg)) { |
1025 | if (queue_work(kmpath_handlerd, &pgpath->activate_path)) | 1047 | if (queue_work(kmpath_handlerd, &pgpath->activate_path.work)) |
1026 | m->pg_init_in_progress++; | 1048 | m->pg_init_in_progress++; |
1027 | } | 1049 | } |
1028 | 1050 | ||
@@ -1157,6 +1179,7 @@ static void pg_init_done(void *data, int errors) | |||
1157 | struct priority_group *pg = pgpath->pg; | 1179 | struct priority_group *pg = pgpath->pg; |
1158 | struct multipath *m = pg->m; | 1180 | struct multipath *m = pg->m; |
1159 | unsigned long flags; | 1181 | unsigned long flags; |
1182 | unsigned delay_retry = 0; | ||
1160 | 1183 | ||
1161 | /* device or driver problems */ | 1184 | /* device or driver problems */ |
1162 | switch (errors) { | 1185 | switch (errors) { |
@@ -1181,8 +1204,9 @@ static void pg_init_done(void *data, int errors) | |||
1181 | */ | 1204 | */ |
1182 | bypass_pg(m, pg, 1); | 1205 | bypass_pg(m, pg, 1); |
1183 | break; | 1206 | break; |
1184 | /* TODO: For SCSI_DH_RETRY we should wait a couple seconds */ | ||
1185 | case SCSI_DH_RETRY: | 1207 | case SCSI_DH_RETRY: |
1208 | /* Wait before retrying. */ | ||
1209 | delay_retry = 1; | ||
1186 | case SCSI_DH_IMM_RETRY: | 1210 | case SCSI_DH_IMM_RETRY: |
1187 | case SCSI_DH_RES_TEMP_UNAVAIL: | 1211 | case SCSI_DH_RES_TEMP_UNAVAIL: |
1188 | if (pg_init_limit_reached(m, pgpath)) | 1212 | if (pg_init_limit_reached(m, pgpath)) |
@@ -1215,6 +1239,7 @@ static void pg_init_done(void *data, int errors) | |||
1215 | if (!m->pg_init_required) | 1239 | if (!m->pg_init_required) |
1216 | m->queue_io = 0; | 1240 | m->queue_io = 0; |
1217 | 1241 | ||
1242 | m->pg_init_delay_retry = delay_retry; | ||
1218 | queue_work(kmultipathd, &m->process_queued_ios); | 1243 | queue_work(kmultipathd, &m->process_queued_ios); |
1219 | 1244 | ||
1220 | /* | 1245 | /* |
@@ -1229,7 +1254,7 @@ out: | |||
1229 | static void activate_path(struct work_struct *work) | 1254 | static void activate_path(struct work_struct *work) |
1230 | { | 1255 | { |
1231 | struct pgpath *pgpath = | 1256 | struct pgpath *pgpath = |
1232 | container_of(work, struct pgpath, activate_path); | 1257 | container_of(work, struct pgpath, activate_path.work); |
1233 | 1258 | ||
1234 | scsi_dh_activate(bdev_get_queue(pgpath->path.dev->bdev), | 1259 | scsi_dh_activate(bdev_get_queue(pgpath->path.dev->bdev), |
1235 | pg_init_done, pgpath); | 1260 | pg_init_done, pgpath); |
@@ -1370,11 +1395,14 @@ static int multipath_status(struct dm_target *ti, status_type_t type, | |||
1370 | DMEMIT("2 %u %u ", m->queue_size, m->pg_init_count); | 1395 | DMEMIT("2 %u %u ", m->queue_size, m->pg_init_count); |
1371 | else { | 1396 | else { |
1372 | DMEMIT("%u ", m->queue_if_no_path + | 1397 | DMEMIT("%u ", m->queue_if_no_path + |
1373 | (m->pg_init_retries > 0) * 2); | 1398 | (m->pg_init_retries > 0) * 2 + |
1399 | (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT) * 2); | ||
1374 | if (m->queue_if_no_path) | 1400 | if (m->queue_if_no_path) |
1375 | DMEMIT("queue_if_no_path "); | 1401 | DMEMIT("queue_if_no_path "); |
1376 | if (m->pg_init_retries) | 1402 | if (m->pg_init_retries) |
1377 | DMEMIT("pg_init_retries %u ", m->pg_init_retries); | 1403 | DMEMIT("pg_init_retries %u ", m->pg_init_retries); |
1404 | if (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT) | ||
1405 | DMEMIT("pg_init_delay_msecs %u ", m->pg_init_delay_msecs); | ||
1378 | } | 1406 | } |
1379 | 1407 | ||
1380 | if (!m->hw_handler_name || type == STATUSTYPE_INFO) | 1408 | if (!m->hw_handler_name || type == STATUSTYPE_INFO) |
@@ -1643,7 +1671,7 @@ out: | |||
1643 | *---------------------------------------------------------------*/ | 1671 | *---------------------------------------------------------------*/ |
1644 | static struct target_type multipath_target = { | 1672 | static struct target_type multipath_target = { |
1645 | .name = "multipath", | 1673 | .name = "multipath", |
1646 | .version = {1, 1, 1}, | 1674 | .version = {1, 2, 0}, |
1647 | .module = THIS_MODULE, | 1675 | .module = THIS_MODULE, |
1648 | .ctr = multipath_ctr, | 1676 | .ctr = multipath_ctr, |
1649 | .dtr = multipath_dtr, | 1677 | .dtr = multipath_dtr, |