File multipath-tools-implement-dev_loss_tmo of Package multipath-tools

From 4c6e3b7eff9825353610bfc3130276e6f5233247 Mon Sep 17 00:00:00 2001
From: Hannes Reinecke <hare@suse.de>
Date: Tue, 13 Jan 2009 16:01:30 +0100
Subject: [PATCH] Implement dev_loss_tmo and fast_io_fail_tmo

When using multipath the 'dev_loss_tmo' and 'fast_io_fail_tmo'
settings should be as small as possible to avoid any stalls
in multipathd. So we should be able to configure both
from within mulitpath.

Signed-off-by: Hannes Reinecke <hare@suse.de>
---
 libmultipath/config.c      |    2 +
 libmultipath/config.h      |    4 +
 libmultipath/dict.c        |  144 ++++++++++++++++++++++++++++++++++++++++++++
 libmultipath/discovery.c   |  104 +++++++++++++++++++++++++++++++
 libmultipath/discovery.h   |    1 +
 libmultipath/structs_vec.c |    6 ++
 multipath/multipath.conf.5 |   12 ++++
 7 files changed, 273 insertions(+), 0 deletions(-)

diff --git a/libmultipath/config.c b/libmultipath/config.c
index 83da6e7..ea7ad99 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -463,6 +463,8 @@ load_config (char * file)
 	conf->dev_type = DEV_NONE;
 	conf->minio = 1000;
 	conf->max_fds = 0;
+	conf->dev_loss_tmo = 0;
+	conf->fast_io_fail_tmo = 0;
 	conf->multipath_dir = set_default(DEFAULT_MULTIPATHDIR);
 
 	/*
diff --git a/libmultipath/config.h b/libmultipath/config.h
index fc0e22d..7d23927 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -29,6 +29,8 @@ struct hwentry {
 	int no_path_retry;
 	int minio;
 	int pg_timeout;
+	int dev_loss_tmo;
+	int fast_io_fail_tmo;
 	char * bl_product;
 };
 
@@ -67,6 +69,8 @@ struct config {
 	int pg_timeout;
 	int max_fds;
 	int force_reload;
+	int dev_loss_tmo;
+	int fast_io_fail_tmo;
 
 	char * dev;
 	char * sysfs_dir;
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index 09ecf51..ed77000 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -189,6 +189,46 @@ max_fds_handler(vector strvec)
 }
 
 static int
+def_dev_loss_tmo_handler(vector strvec)
+{
+	char * buff;
+
+	buff = set_value(strvec);
+
+	if (!buff)
+		return 1;
+
+	if (strlen(buff) == 9 &&
+	    !strcmp(buff, "off"))
+		conf->dev_loss_tmo = -1;
+	else
+		conf->dev_loss_tmo = atoi(buff);
+	FREE(buff);
+
+	return 0;
+}
+
+static int
+def_fast_io_fail_tmo_handler(vector strvec)
+{
+	char * buff;
+
+	buff = set_value(strvec);
+
+	if (!buff)
+		return 1;
+
+	if (strlen(buff) == 9 &&
+	    !strcmp(buff, "off"))
+		conf->fast_io_fail_tmo = -1;
+	else
+		conf->fast_io_fail_tmo = atoi(buff);
+	FREE(buff);
+
+	return 0;
+}
+
+static int
 def_weight_handler(vector strvec)
 {
 	char * buff;
@@ -779,6 +819,54 @@ hw_pg_timeout_handler(vector strvec)
 	return 0;
 }
 
+static int
+hw_dev_loss_tmo_handler(vector strvec)
+{
+	struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
+	char * buff;
+
+	if (!hwe)
+		return 1;
+
+	buff = set_value(strvec);
+
+	if (!buff)
+		return 1;
+
+	if (strlen(buff) == 9 &&
+	    !strcmp(buff, "off"))
+		hwe->dev_loss_tmo = -1;
+	else
+		hwe->dev_loss_tmo = atoi(buff);
+	FREE(buff);
+
+	return 0;
+}
+
+static int
+hw_fast_io_fail_tmo_handler(vector strvec)
+{
+	struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
+	char * buff;
+
+	if (!hwe)
+		return 1;
+
+	buff = set_value(strvec);
+
+	if (!buff)
+		return 1;
+
+	if (strlen(buff) == 9 &&
+	    !strcmp(buff, "off"))
+		hwe->fast_io_fail_tmo = -1;
+	else
+		hwe->fast_io_fail_tmo = atoi(buff);
+	FREE(buff);
+
+	return 0;
+}
+
 /*
  * multipaths block handlers
  */
@@ -1406,6 +1494,36 @@ snprint_hw_path_checker (char * buff, int len, void * data)
 }
 
 static int
+snprint_hw_dev_loss_tmo (char * buff, int len, void * data)
+{
+	struct hwentry * hwe = (struct hwentry *)data;
+
+	if (!hwe->dev_loss_tmo)
+		return 0;
+	if (hwe->dev_loss_tmo == conf->dev_loss_tmo)
+		return 0;
+
+	if (hwe->dev_loss_tmo < 0)
+		return snprintf(buff, len, "off");
+	return snprintf(buff, len, "%u", hwe->dev_loss_tmo);
+}
+
+static int
+snprint_hw_fast_io_fail_tmo (char * buff, int len, void * data)
+{
+	struct hwentry * hwe = (struct hwentry *)data;
+
+	if (!hwe->fast_io_fail_tmo)
+		return 0;
+	if (hwe->fast_io_fail_tmo == conf->fast_io_fail_tmo)
+		return 0;
+
+	if (hwe->fast_io_fail_tmo < 0)
+		return snprintf(buff, len, "off");
+	return snprintf(buff, len, "%u", hwe->fast_io_fail_tmo);
+}
+
+static int
 snprint_def_polling_interval (char * buff, int len, void * data)
 {
 	if (conf->checkint == DEFAULT_CHECKINT)
@@ -1565,6 +1683,28 @@ snprint_max_fds (char * buff, int len, void * data)
 }
 
 static int
+snprint_def_dev_loss_tmo (char * buff, int len, void * data)
+{
+	if (!conf->dev_loss_tmo)
+		return 0;
+
+	if (conf->dev_loss_tmo < 0)
+		return snprintf(buff, len, "off");
+	return snprintf(buff, len, "%d", conf->dev_loss_tmo);
+}
+
+static int
+snprint_def_fast_io_fail_tmo (char * buff, int len, void * data)
+{
+	if (!conf->fast_io_fail_tmo)
+		return 0;
+
+	if (conf->fast_io_fail_tmo < 0)
+		return snprintf(buff, len, "off");
+	return snprintf(buff, len, "%d", conf->fast_io_fail_tmo);
+}
+
+static int
 snprint_def_rr_weight (char * buff, int len, void * data)
 {
 	if (!conf->rr_weight)
@@ -1681,6 +1821,8 @@ init_keywords(void)
 	install_keyword("failback", &default_failback_handler, &snprint_def_failback);
 	install_keyword("rr_min_io", &def_minio_handler, &snprint_def_rr_min_io);
 	install_keyword("max_fds", &max_fds_handler, &snprint_max_fds);
+	install_keyword("dev_loss_tmo", &def_dev_loss_tmo_handler, &snprint_def_dev_loss_tmo);
+	install_keyword("fast_io_fail_tmo", &def_fast_io_fail_tmo_handler, &snprint_def_fast_io_fail_tmo);
 	install_keyword("rr_weight", &def_weight_handler, &snprint_def_rr_weight);
 	install_keyword("no_path_retry", &def_no_path_retry_handler, &snprint_def_no_path_retry);
 	install_keyword("pg_timeout", &def_pg_timeout_handler, &snprint_def_pg_timeout);
@@ -1739,6 +1881,8 @@ init_keywords(void)
 	install_keyword("no_path_retry", &hw_no_path_retry_handler, &snprint_hw_no_path_retry);
 	install_keyword("rr_min_io", &hw_minio_handler, &snprint_hw_rr_min_io);
 	install_keyword("pg_timeout", &hw_pg_timeout_handler, &snprint_hw_pg_timeout);
+	install_keyword("dev_loss_tmo", &hw_dev_loss_tmo_handler, &snprint_hw_dev_loss_tmo);
+	install_keyword("fast_io_fail_tmo", &hw_fast_io_fail_tmo_handler, &snprint_hw_fast_io_fail_tmo);
 	install_sublevel_end();
 
 	install_keyword_root("multipaths", &multipaths_handler);
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index afd247d..6e4ce1e 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -209,6 +209,110 @@ sysfs_get_fc_nodename (struct sysfs_device * dev, char * node,
 	return 1;
 }
 
+int
+sysfs_set_fc_values (struct path *pp, int dev_loss_tmo, int fast_io_fail_tmo)
+{
+	char attr_path[SYSFS_PATH_SIZE];
+	char host_path[SYSFS_PATH_SIZE];
+	char attr_value[NAME_SIZE];
+	DIR *host_dir, *rport_dir;
+	struct dirent *host_ent, *rport_ent;
+	int host, channel, lun, port, num;
+	int rport_channel = -1;
+	int rport_id = -1;
+
+	if (dev_loss_tmo == 0 || fast_io_fail_tmo == 0) {
+		condlog(4, "%s: no FC settings", pp->dev);
+		return 0;
+	}
+
+	if (safe_sprintf(host_path, "/sys/class/fc_host/host%i/device",
+			 pp->sg_id.host_no)) {
+		condlog(0, "host_path too small");
+		return 1;
+	}
+	if (!(host_dir = opendir(host_path))) {
+		condlog(3, "host %d not a FC HBA", pp->sg_id.host_no);
+		return 0;
+	}
+
+	while (rport_channel < 0 && rport_id < 0 &&
+	       (host_ent = readdir(host_dir))) {
+		if (sscanf(host_ent->d_name, "rport-%d:%d-%d",
+			   &host, &port, &num) != 3)
+			continue;
+
+		if (host != pp->sg_id.host_no)
+			continue;
+
+		if (safe_sprintf(attr_path, "%s/%s",
+				 host_path, host_ent->d_name)) {
+			condlog(0, "target_path too small");
+			continue;
+		}
+
+		if (!(rport_dir = opendir(attr_path))) {
+			condlog(1, "cannot open rport path '%s'", attr_path);
+			continue;
+		}
+
+		while ((rport_ent = readdir(rport_dir))) {
+			if (sscanf(rport_ent->d_name, "target%d:%d:%d",
+				   &host, &channel, &lun) != 3)
+				continue;
+
+			if (host != pp->sg_id.host_no &&
+			    channel != pp->sg_id.channel &&
+			    lun != pp->sg_id.scsi_id)
+				continue;
+
+			rport_channel = port;
+			rport_id = num;
+			break;
+		}
+	}
+
+	if (rport_channel < 0 && rport_id < 0) {
+		condlog(1, "No rport found");
+		return 0;
+	}
+
+	if (safe_sprintf(attr_path,
+			"/class/fc_remote_ports/rport-%d:%d-%d",
+			pp->sg_id.host_no, rport_channel, rport_id)) {
+		condlog(0, "attr_path too small");
+		return 0;
+	}
+
+	if (dev_loss_tmo < 0)
+		sprintf(attr_value, "%d", 0);
+	else
+		sprintf(attr_value, "%d", dev_loss_tmo);
+	num = sysfs_attr_set_value(attr_path, "dev_loss_tmo",
+				   attr_value, strlen(attr_value));
+	if (num > 0)
+		condlog(4, "%s: set dev_loss_tmo to %d", pp->dev,
+			dev_loss_tmo);
+	else
+		condlog(4, "%s: failed to set dev_loss_tmo (%d)",
+			pp->dev, errno);
+
+	if (fast_io_fail_tmo < 0)
+		sprintf(attr_value, "%d", 0);
+	else
+		sprintf(attr_value, "%d", fast_io_fail_tmo);
+	num = sysfs_attr_set_value(attr_path, "fast_io_fail_tmo",
+				   attr_value, strlen(attr_value));
+	if (num > 0)
+		condlog(4, "%s: set fast_io_fail_tmo to %d", pp->dev,
+			fast_io_fail_tmo);
+	else
+		condlog(4, "%s: failed to set fast_io_fail_tmo (%d)",
+			pp->dev, errno);
+
+	return num == strlen(attr_value) ? 0 : 1;
+}
+
 static int
 opennode (char * dev, int mode)
 {
diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h
index 05b1cfe..3749674 100644
--- a/libmultipath/discovery.h
+++ b/libmultipath/discovery.h
@@ -32,6 +32,7 @@ int devt2devname (char *, char *);
 int pathinfo (struct path *, vector hwtable, int mask);
 struct path * store_pathinfo (vector pathvec, vector hwtable,
 			      char * devname, int flag);
+int sysfs_set_fc_values (struct path *pp, int dev_loss_tmo, int fast_io_fail_tmo);
 
 /*
  * discovery bitmask
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
index a1d9632..1632c9d 100644
--- a/libmultipath/structs_vec.c
+++ b/libmultipath/structs_vec.c
@@ -479,6 +479,12 @@ verify_paths(struct multipath * mpp, struct vectors * vecs, vector rpvec)
 				free_path(pp);
 			}
 		} else {
+			if (pp->hwe)
+				sysfs_set_fc_values(pp, pp->hwe->dev_loss_tmo,
+						    pp->hwe->fast_io_fail_tmo);
+			else
+				sysfs_set_fc_values(pp, conf->dev_loss_tmo,
+						    conf->fast_io_fail_tmo);
 			condlog(4, "%s: verified path %s dev_t %s",
 				mpp->alias, pp->dev, pp->dev_t);
 		}
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
index 8ac1f1c..926ff69 100644
--- a/multipath/multipath.conf.5
+++ b/multipath/multipath.conf.5
@@ -263,6 +263,14 @@ Default is
 .B bindings_file
 The full pathname of the binding file to be used when the user_friendly_names option is set. Defaults to
 .I /var/lib/multipath/bindings
+.TP
+.B dev_loss_tmo
+The default dev_loss_tmo setting for an FC remote port in seconds. If an rport has vanished from the fabric all devices on that port will be removed from sysfs after this timeout.
+.TP
+.B fast_io_fail_tmo
+The default fast_io_fail_tmo setting for an FC remote port in seconds. If an rport has vanished from the fabric all I/O to the devices on that port will be terminated after this timeout. Should be smaller than
+.B dev_loss_tmo
+setting.
 .
 .SH "blacklist section"
 The
@@ -413,6 +421,10 @@ section:
 .B no_path_retry
 .TP
 .B rr_min_io
+.TP
+.B dev_loss_tmo
+.TP
+.B fast_io_fail_tmo
 .RE
 .PD
 .LP
-- 
1.5.3.2

openSUSE Build Service is sponsored by