aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDave Wysochanski <dwysocha@redhat.com>2007-10-19 17:47:53 -0400
committerAlasdair G Kergon <agk@redhat.com>2007-10-19 21:01:18 -0400
commitc9e45581ad530cc1ca4b5d4add44a5b625234ada (patch)
tree3d5ddc7762e9c3d3da78f8c4d98047f3f108dd98 /drivers
parent636d5786c45414fd8e48f2a2325be072274fdba4 (diff)
dm mpath: add retry pg init
This patch allows a failed path group initialisation command to be retried. It adds a generic MP_RETRY flag and a "pg_init_retries" feature to device-mapper multipath which limits the number of retries. 1. A hw handler sends a path initialization command to the storage and the command completes with an error code indicating the command should be retried. 2. The hardware handler calls dm_pg_init_complete() with MP_RETRY set in err_flags to ask the dm multipath core to retry. 3. If the retry limit has not been exceeded, pg_init() is retried. Otherwise fail_path() is called. If you are using the userspace multipath-tools or device-mapper-multipath package, you can set pg_init_retries in the 'device' section of your /etc/multipath.conf file. For example: features "2 pg_init_retries 7" The number of PG retries attempted is reported in the 'dmsetup status' output. Signed-off-by: Dave Wysochanski <dwysocha@redhat.com> Acked-by: Mike Christie <michaelc@cs.wisc.edu> Acked-by: Chandra Seetharaman <sekharan@us.ibm.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/md/dm-hw-handler.h1
-rw-r--r--drivers/md/dm-mpath.c81
2 files changed, 68 insertions, 14 deletions
diff --git a/drivers/md/dm-hw-handler.h b/drivers/md/dm-hw-handler.h
index e0832e6fcf36..46809dcb121a 100644
--- a/drivers/md/dm-hw-handler.h
+++ b/drivers/md/dm-hw-handler.h
@@ -58,5 +58,6 @@ unsigned dm_scsi_err_handler(struct hw_handler *hwh, struct bio *bio);
58#define MP_FAIL_PATH 1 58#define MP_FAIL_PATH 1
59#define MP_BYPASS_PG 2 59#define MP_BYPASS_PG 2
60#define MP_ERROR_IO 4 /* Don't retry this I/O */ 60#define MP_ERROR_IO 4 /* Don't retry this I/O */
61#define MP_RETRY 8
61 62
62#endif 63#endif
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 31056abca89d..dd5ad6310f54 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -75,6 +75,8 @@ struct multipath {
75 unsigned queue_io; /* Must we queue all I/O? */ 75 unsigned queue_io; /* Must we queue all I/O? */
76 unsigned queue_if_no_path; /* Queue I/O if last path fails? */ 76 unsigned queue_if_no_path; /* Queue I/O if last path fails? */
77 unsigned saved_queue_if_no_path;/* Saved state during suspension */ 77 unsigned saved_queue_if_no_path;/* Saved state during suspension */
78 unsigned pg_init_retries; /* Number of times to retry pg_init */
79 unsigned pg_init_count; /* Number of times pg_init called */
78 80
79 struct work_struct process_queued_ios; 81 struct work_struct process_queued_ios;
80 struct bio_list queued_ios; 82 struct bio_list queued_ios;
@@ -225,6 +227,8 @@ static void __switch_pg(struct multipath *m, struct pgpath *pgpath)
225 m->pg_init_required = 0; 227 m->pg_init_required = 0;
226 m->queue_io = 0; 228 m->queue_io = 0;
227 } 229 }
230
231 m->pg_init_count = 0;
228} 232}
229 233
230static int __choose_path_in_pg(struct multipath *m, struct priority_group *pg) 234static int __choose_path_in_pg(struct multipath *m, struct priority_group *pg)
@@ -424,6 +428,7 @@ static void process_queued_ios(struct work_struct *work)
424 must_queue = 0; 428 must_queue = 0;
425 429
426 if (m->pg_init_required && !m->pg_init_in_progress) { 430 if (m->pg_init_required && !m->pg_init_in_progress) {
431 m->pg_init_count++;
427 m->pg_init_required = 0; 432 m->pg_init_required = 0;
428 m->pg_init_in_progress = 1; 433 m->pg_init_in_progress = 1;
429 init_required = 1; 434 init_required = 1;
@@ -689,9 +694,11 @@ static int parse_features(struct arg_set *as, struct multipath *m)
689 int r; 694 int r;
690 unsigned argc; 695 unsigned argc;
691 struct dm_target *ti = m->ti; 696 struct dm_target *ti = m->ti;
697 const char *param_name;
692 698
693 static struct param _params[] = { 699 static struct param _params[] = {
694 {0, 1, "invalid number of feature args"}, 700 {0, 3, "invalid number of feature args"},
701 {1, 50, "pg_init_retries must be between 1 and 50"},
695 }; 702 };
696 703
697 r = read_param(_params, shift(as), &argc, &ti->error); 704 r = read_param(_params, shift(as), &argc, &ti->error);
@@ -701,12 +708,28 @@ static int parse_features(struct arg_set *as, struct multipath *m)
701 if (!argc) 708 if (!argc)
702 return 0; 709 return 0;
703 710
704 if (!strnicmp(shift(as), MESG_STR("queue_if_no_path"))) 711 do {
705 return queue_if_no_path(m, 1, 0); 712 param_name = shift(as);
706 else { 713 argc--;
714
715 if (!strnicmp(param_name, MESG_STR("queue_if_no_path"))) {
716 r = queue_if_no_path(m, 1, 0);
717 continue;
718 }
719
720 if (!strnicmp(param_name, MESG_STR("pg_init_retries")) &&
721 (argc >= 1)) {
722 r = read_param(_params + 1, shift(as),
723 &m->pg_init_retries, &ti->error);
724 argc--;
725 continue;
726 }
727
707 ti->error = "Unrecognised multipath feature request"; 728 ti->error = "Unrecognised multipath feature request";
708 return -EINVAL; 729 r = -EINVAL;
709 } 730 } while (argc && !r);
731
732 return r;
710} 733}
711 734
712static int multipath_ctr(struct dm_target *ti, unsigned int argc, 735static int multipath_ctr(struct dm_target *ti, unsigned int argc,
@@ -976,6 +999,26 @@ static int bypass_pg_num(struct multipath *m, const char *pgstr, int bypassed)
976} 999}
977 1000
978/* 1001/*
1002 * Should we retry pg_init immediately?
1003 */
1004static int pg_init_limit_reached(struct multipath *m, struct pgpath *pgpath)
1005{
1006 unsigned long flags;
1007 int limit_reached = 0;
1008
1009 spin_lock_irqsave(&m->lock, flags);
1010
1011 if (m->pg_init_count <= m->pg_init_retries)
1012 m->pg_init_required = 1;
1013 else
1014 limit_reached = 1;
1015
1016 spin_unlock_irqrestore(&m->lock, flags);
1017
1018 return limit_reached;
1019}
1020
1021/*
979 * pg_init must call this when it has completed its initialisation 1022 * pg_init must call this when it has completed its initialisation
980 */ 1023 */
981void dm_pg_init_complete(struct dm_path *path, unsigned err_flags) 1024void dm_pg_init_complete(struct dm_path *path, unsigned err_flags)
@@ -985,8 +1028,14 @@ void dm_pg_init_complete(struct dm_path *path, unsigned err_flags)
985 struct multipath *m = pg->m; 1028 struct multipath *m = pg->m;
986 unsigned long flags; 1029 unsigned long flags;
987 1030
988 /* We insist on failing the path if the PG is already bypassed. */ 1031 /*
989 if (err_flags && pg->bypassed) 1032 * If requested, retry pg_init until maximum number of retries exceeded.
1033 * If retry not requested and PG already bypassed, always fail the path.
1034 */
1035 if (err_flags & MP_RETRY) {
1036 if (pg_init_limit_reached(m, pgpath))
1037 err_flags |= MP_FAIL_PATH;
1038 } else if (err_flags && pg->bypassed)
990 err_flags |= MP_FAIL_PATH; 1039 err_flags |= MP_FAIL_PATH;
991 1040
992 if (err_flags & MP_FAIL_PATH) 1041 if (err_flags & MP_FAIL_PATH)
@@ -996,7 +1045,7 @@ void dm_pg_init_complete(struct dm_path *path, unsigned err_flags)
996 bypass_pg(m, pg, 1); 1045 bypass_pg(m, pg, 1);
997 1046
998 spin_lock_irqsave(&m->lock, flags); 1047 spin_lock_irqsave(&m->lock, flags);
999 if (err_flags) { 1048 if (err_flags & ~MP_RETRY) {
1000 m->current_pgpath = NULL; 1049 m->current_pgpath = NULL;
1001 m->current_pg = NULL; 1050 m->current_pg = NULL;
1002 } else if (!m->pg_init_required) 1051 } else if (!m->pg_init_required)
@@ -1148,11 +1197,15 @@ static int multipath_status(struct dm_target *ti, status_type_t type,
1148 1197
1149 /* Features */ 1198 /* Features */
1150 if (type == STATUSTYPE_INFO) 1199 if (type == STATUSTYPE_INFO)
1151 DMEMIT("1 %u ", m->queue_size); 1200 DMEMIT("2 %u %u ", m->queue_size, m->pg_init_count);
1152 else if (m->queue_if_no_path) 1201 else {
1153 DMEMIT("1 queue_if_no_path "); 1202 DMEMIT("%u ", m->queue_if_no_path +
1154 else 1203 (m->pg_init_retries > 0) * 2);
1155 DMEMIT("0 "); 1204 if (m->queue_if_no_path)
1205 DMEMIT("queue_if_no_path ");
1206 if (m->pg_init_retries)
1207 DMEMIT("pg_init_retries %u ", m->pg_init_retries);
1208 }
1156 1209
1157 if (hwh->type && hwh->type->status) 1210 if (hwh->type && hwh->type->status)
1158 sz += hwh->type->status(hwh, type, result + sz, maxlen - sz); 1211 sz += hwh->type->status(hwh, type, result + sz, maxlen - sz);