diff options
author | Steve French <sfrench@us.ibm.com> | 2007-10-20 00:26:44 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2007-10-20 00:26:44 -0400 |
commit | 748c5151deb56e4b7b5a9b07a884243764933831 (patch) | |
tree | e9dd45b8806d00b56503cfa55c46f3ebce0d151c /drivers/md/dm-mpath.c | |
parent | 4879b44829d94a1f8facf90cced3c5f23c5a8c62 (diff) | |
parent | e8b8c977734193adedf2b0f607d6252c78e86394 (diff) |
Merge branch 'master' of /pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'drivers/md/dm-mpath.c')
-rw-r--r-- | drivers/md/dm-mpath.c | 88 |
1 files changed, 74 insertions, 14 deletions
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 31056abca89d..24b2b1e32fae 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include "dm-hw-handler.h" | 10 | #include "dm-hw-handler.h" |
11 | #include "dm-bio-list.h" | 11 | #include "dm-bio-list.h" |
12 | #include "dm-bio-record.h" | 12 | #include "dm-bio-record.h" |
13 | #include "dm-uevent.h" | ||
13 | 14 | ||
14 | #include <linux/ctype.h> | 15 | #include <linux/ctype.h> |
15 | #include <linux/init.h> | 16 | #include <linux/init.h> |
@@ -75,6 +76,8 @@ struct multipath { | |||
75 | unsigned queue_io; /* Must we queue all I/O? */ | 76 | unsigned queue_io; /* Must we queue all I/O? */ |
76 | unsigned queue_if_no_path; /* Queue I/O if last path fails? */ | 77 | unsigned queue_if_no_path; /* Queue I/O if last path fails? */ |
77 | unsigned saved_queue_if_no_path;/* Saved state during suspension */ | 78 | unsigned saved_queue_if_no_path;/* Saved state during suspension */ |
79 | unsigned pg_init_retries; /* Number of times to retry pg_init */ | ||
80 | unsigned pg_init_count; /* Number of times pg_init called */ | ||
78 | 81 | ||
79 | struct work_struct process_queued_ios; | 82 | struct work_struct process_queued_ios; |
80 | struct bio_list queued_ios; | 83 | struct bio_list queued_ios; |
@@ -225,6 +228,8 @@ static void __switch_pg(struct multipath *m, struct pgpath *pgpath) | |||
225 | m->pg_init_required = 0; | 228 | m->pg_init_required = 0; |
226 | m->queue_io = 0; | 229 | m->queue_io = 0; |
227 | } | 230 | } |
231 | |||
232 | m->pg_init_count = 0; | ||
228 | } | 233 | } |
229 | 234 | ||
230 | static int __choose_path_in_pg(struct multipath *m, struct priority_group *pg) | 235 | static int __choose_path_in_pg(struct multipath *m, struct priority_group *pg) |
@@ -424,6 +429,7 @@ static void process_queued_ios(struct work_struct *work) | |||
424 | must_queue = 0; | 429 | must_queue = 0; |
425 | 430 | ||
426 | if (m->pg_init_required && !m->pg_init_in_progress) { | 431 | if (m->pg_init_required && !m->pg_init_in_progress) { |
432 | m->pg_init_count++; | ||
427 | m->pg_init_required = 0; | 433 | m->pg_init_required = 0; |
428 | m->pg_init_in_progress = 1; | 434 | m->pg_init_in_progress = 1; |
429 | init_required = 1; | 435 | init_required = 1; |
@@ -689,9 +695,11 @@ static int parse_features(struct arg_set *as, struct multipath *m) | |||
689 | int r; | 695 | int r; |
690 | unsigned argc; | 696 | unsigned argc; |
691 | struct dm_target *ti = m->ti; | 697 | struct dm_target *ti = m->ti; |
698 | const char *param_name; | ||
692 | 699 | ||
693 | static struct param _params[] = { | 700 | static struct param _params[] = { |
694 | {0, 1, "invalid number of feature args"}, | 701 | {0, 3, "invalid number of feature args"}, |
702 | {1, 50, "pg_init_retries must be between 1 and 50"}, | ||
695 | }; | 703 | }; |
696 | 704 | ||
697 | r = read_param(_params, shift(as), &argc, &ti->error); | 705 | r = read_param(_params, shift(as), &argc, &ti->error); |
@@ -701,12 +709,28 @@ static int parse_features(struct arg_set *as, struct multipath *m) | |||
701 | if (!argc) | 709 | if (!argc) |
702 | return 0; | 710 | return 0; |
703 | 711 | ||
704 | if (!strnicmp(shift(as), MESG_STR("queue_if_no_path"))) | 712 | do { |
705 | return queue_if_no_path(m, 1, 0); | 713 | param_name = shift(as); |
706 | else { | 714 | argc--; |
715 | |||
716 | if (!strnicmp(param_name, MESG_STR("queue_if_no_path"))) { | ||
717 | r = queue_if_no_path(m, 1, 0); | ||
718 | continue; | ||
719 | } | ||
720 | |||
721 | if (!strnicmp(param_name, MESG_STR("pg_init_retries")) && | ||
722 | (argc >= 1)) { | ||
723 | r = read_param(_params + 1, shift(as), | ||
724 | &m->pg_init_retries, &ti->error); | ||
725 | argc--; | ||
726 | continue; | ||
727 | } | ||
728 | |||
707 | ti->error = "Unrecognised multipath feature request"; | 729 | ti->error = "Unrecognised multipath feature request"; |
708 | return -EINVAL; | 730 | r = -EINVAL; |
709 | } | 731 | } while (argc && !r); |
732 | |||
733 | return r; | ||
710 | } | 734 | } |
711 | 735 | ||
712 | static int multipath_ctr(struct dm_target *ti, unsigned int argc, | 736 | static int multipath_ctr(struct dm_target *ti, unsigned int argc, |
@@ -834,6 +858,9 @@ static int fail_path(struct pgpath *pgpath) | |||
834 | if (pgpath == m->current_pgpath) | 858 | if (pgpath == m->current_pgpath) |
835 | m->current_pgpath = NULL; | 859 | m->current_pgpath = NULL; |
836 | 860 | ||
861 | dm_path_uevent(DM_UEVENT_PATH_FAILED, m->ti, | ||
862 | pgpath->path.dev->name, m->nr_valid_paths); | ||
863 | |||
837 | queue_work(kmultipathd, &m->trigger_event); | 864 | queue_work(kmultipathd, &m->trigger_event); |
838 | 865 | ||
839 | out: | 866 | out: |
@@ -873,6 +900,9 @@ static int reinstate_path(struct pgpath *pgpath) | |||
873 | if (!m->nr_valid_paths++ && m->queue_size) | 900 | if (!m->nr_valid_paths++ && m->queue_size) |
874 | queue_work(kmultipathd, &m->process_queued_ios); | 901 | queue_work(kmultipathd, &m->process_queued_ios); |
875 | 902 | ||
903 | dm_path_uevent(DM_UEVENT_PATH_REINSTATED, m->ti, | ||
904 | pgpath->path.dev->name, m->nr_valid_paths); | ||
905 | |||
876 | queue_work(kmultipathd, &m->trigger_event); | 906 | queue_work(kmultipathd, &m->trigger_event); |
877 | 907 | ||
878 | out: | 908 | out: |
@@ -976,6 +1006,26 @@ static int bypass_pg_num(struct multipath *m, const char *pgstr, int bypassed) | |||
976 | } | 1006 | } |
977 | 1007 | ||
978 | /* | 1008 | /* |
1009 | * Should we retry pg_init immediately? | ||
1010 | */ | ||
1011 | static int pg_init_limit_reached(struct multipath *m, struct pgpath *pgpath) | ||
1012 | { | ||
1013 | unsigned long flags; | ||
1014 | int limit_reached = 0; | ||
1015 | |||
1016 | spin_lock_irqsave(&m->lock, flags); | ||
1017 | |||
1018 | if (m->pg_init_count <= m->pg_init_retries) | ||
1019 | m->pg_init_required = 1; | ||
1020 | else | ||
1021 | limit_reached = 1; | ||
1022 | |||
1023 | spin_unlock_irqrestore(&m->lock, flags); | ||
1024 | |||
1025 | return limit_reached; | ||
1026 | } | ||
1027 | |||
1028 | /* | ||
979 | * pg_init must call this when it has completed its initialisation | 1029 | * pg_init must call this when it has completed its initialisation |
980 | */ | 1030 | */ |
981 | void dm_pg_init_complete(struct dm_path *path, unsigned err_flags) | 1031 | void dm_pg_init_complete(struct dm_path *path, unsigned err_flags) |
@@ -985,8 +1035,14 @@ void dm_pg_init_complete(struct dm_path *path, unsigned err_flags) | |||
985 | struct multipath *m = pg->m; | 1035 | struct multipath *m = pg->m; |
986 | unsigned long flags; | 1036 | unsigned long flags; |
987 | 1037 | ||
988 | /* We insist on failing the path if the PG is already bypassed. */ | 1038 | /* |
989 | if (err_flags && pg->bypassed) | 1039 | * If requested, retry pg_init until maximum number of retries exceeded. |
1040 | * If retry not requested and PG already bypassed, always fail the path. | ||
1041 | */ | ||
1042 | if (err_flags & MP_RETRY) { | ||
1043 | if (pg_init_limit_reached(m, pgpath)) | ||
1044 | err_flags |= MP_FAIL_PATH; | ||
1045 | } else if (err_flags && pg->bypassed) | ||
990 | err_flags |= MP_FAIL_PATH; | 1046 | err_flags |= MP_FAIL_PATH; |
991 | 1047 | ||
992 | if (err_flags & MP_FAIL_PATH) | 1048 | if (err_flags & MP_FAIL_PATH) |
@@ -996,7 +1052,7 @@ void dm_pg_init_complete(struct dm_path *path, unsigned err_flags) | |||
996 | bypass_pg(m, pg, 1); | 1052 | bypass_pg(m, pg, 1); |
997 | 1053 | ||
998 | spin_lock_irqsave(&m->lock, flags); | 1054 | spin_lock_irqsave(&m->lock, flags); |
999 | if (err_flags) { | 1055 | if (err_flags & ~MP_RETRY) { |
1000 | m->current_pgpath = NULL; | 1056 | m->current_pgpath = NULL; |
1001 | m->current_pg = NULL; | 1057 | m->current_pg = NULL; |
1002 | } else if (!m->pg_init_required) | 1058 | } else if (!m->pg_init_required) |
@@ -1148,11 +1204,15 @@ static int multipath_status(struct dm_target *ti, status_type_t type, | |||
1148 | 1204 | ||
1149 | /* Features */ | 1205 | /* Features */ |
1150 | if (type == STATUSTYPE_INFO) | 1206 | if (type == STATUSTYPE_INFO) |
1151 | DMEMIT("1 %u ", m->queue_size); | 1207 | DMEMIT("2 %u %u ", m->queue_size, m->pg_init_count); |
1152 | else if (m->queue_if_no_path) | 1208 | else { |
1153 | DMEMIT("1 queue_if_no_path "); | 1209 | DMEMIT("%u ", m->queue_if_no_path + |
1154 | else | 1210 | (m->pg_init_retries > 0) * 2); |
1155 | DMEMIT("0 "); | 1211 | if (m->queue_if_no_path) |
1212 | DMEMIT("queue_if_no_path "); | ||
1213 | if (m->pg_init_retries) | ||
1214 | DMEMIT("pg_init_retries %u ", m->pg_init_retries); | ||
1215 | } | ||
1156 | 1216 | ||
1157 | if (hwh->type && hwh->type->status) | 1217 | if (hwh->type && hwh->type->status) |
1158 | sz += hwh->type->status(hwh, type, result + sz, maxlen - sz); | 1218 | sz += hwh->type->status(hwh, type, result + sz, maxlen - sz); |