Blame SOURCES/0057-UP-fix-tmo.patch

4728c8
---
4728c8
 libmultipath/discovery.c |  109 +++++++++++++++++++++++++++++++++++++----------
4728c8
 libmultipath/sysfs.c     |   86 +++++++++++++++++++++++++++++++------
4728c8
 libmultipath/sysfs.h     |    2 
4728c8
 3 files changed, 161 insertions(+), 36 deletions(-)
4728c8
4728c8
Index: multipath-tools-130222/libmultipath/discovery.c
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/libmultipath/discovery.c
4728c8
+++ multipath-tools-130222/libmultipath/discovery.c
4728c8
@@ -162,7 +162,6 @@ declare_sysfs_get_str(cutype);
4728c8
 declare_sysfs_get_str(vendor);
4728c8
 declare_sysfs_get_str(model);
4728c8
 declare_sysfs_get_str(rev);
4728c8
-declare_sysfs_get_str(state);
4728c8
 declare_sysfs_get_str(dev);
4728c8
 
4728c8
 int
4728c8
@@ -315,9 +314,14 @@ static void
4728c8
 sysfs_set_rport_tmo(struct multipath *mpp, struct path *pp)
4728c8
 {
4728c8
 	struct udev_device *rport_dev = NULL;
4728c8
-	char value[11];
4728c8
+	char value[16];
4728c8
 	char rport_id[32];
4728c8
+	int delay_fast_io_fail = 0;
4728c8
+	int current_dev_loss = 0;
4728c8
+	int ret;
4728c8
 
4728c8
+	if (!mpp->dev_loss && mpp->fast_io_fail == MP_FAST_IO_FAIL_UNSET)
4728c8
+		return;
4728c8
 	sprintf(rport_id, "rport-%d:%d-%d",
4728c8
 		pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
4728c8
 	rport_dev = udev_device_new_from_subsystem_sysname(conf->udev,
4728c8
@@ -330,33 +334,85 @@ sysfs_set_rport_tmo(struct multipath *mp
4728c8
 	condlog(4, "target%d:%d:%d -> %s", pp->sg_id.host_no,
4728c8
 		pp->sg_id.channel, pp->sg_id.scsi_id, rport_id);
4728c8
 
4728c8
-	snprintf(value, 11, "%u", mpp->dev_loss);
4728c8
-	if (mpp->dev_loss &&
4728c8
-	    sysfs_attr_set_value(rport_dev, "dev_loss_tmo", value, 11) <= 0) {
4728c8
-		if ((mpp->fast_io_fail == MP_FAST_IO_FAIL_UNSET ||
4728c8
-		     mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF)
4728c8
-		    && mpp->dev_loss > 600) {
4728c8
-			condlog(3, "%s: limiting dev_loss_tmo to 600, since "
4728c8
-				"fast_io_fail is not set", mpp->alias);
4728c8
-			snprintf(value, 11, "%u", 600);
4728c8
-			if (sysfs_attr_set_value(rport_dev, "dev_loss_tmo",
4728c8
-						 value, 11) <= 0)
4728c8
-				condlog(0, "%s failed to set dev_loss_tmo",
4728c8
-					mpp->alias);
4728c8
+	memset(value, 0, 16);
4728c8
+	if (mpp->fast_io_fail != MP_FAST_IO_FAIL_UNSET) {
4728c8
+		ret = sysfs_attr_get_value(rport_dev, "dev_loss_tmo",
4728c8
+					   value, 16);
4728c8
+		if (ret <= 0) {
4728c8
+			condlog(0, "%s: failed to read dev_loss_tmo value, "
4728c8
+				"error %d", rport_id, -ret);
4728c8
 			goto out;
4728c8
 		}
4728c8
+		if (sscanf(value, "%u\n", &current_dev_loss) != 1) {
4728c8
+			condlog(0, "%s: Cannot parse dev_loss_tmo "
4728c8
+				"attribute '%s'", rport_id, value);
4728c8
+			goto out;
4728c8
+		}
4728c8
+		if ((mpp->dev_loss &&
4728c8
+		     mpp->fast_io_fail >= (int)mpp->dev_loss) ||
4728c8
+	            (!mpp->dev_loss &&
4728c8
+                     mpp->fast_io_fail >= (int)current_dev_loss)) {
4728c8
+			condlog(3, "%s: limiting fast_io_fail_tmo to %d, since "
4728c8
+                        	"it must be less than dev_loss_tmo",
4728c8
+				rport_id, mpp->dev_loss - 1);
4728c8
+			if (mpp->dev_loss)
4728c8
+				mpp->fast_io_fail = mpp->dev_loss - 1;
4728c8
+			else
4728c8
+				mpp->fast_io_fail = current_dev_loss - 1;
4728c8
+		}
4728c8
+		if (mpp->fast_io_fail >= (int)current_dev_loss)
4728c8
+			delay_fast_io_fail = 1;
4728c8
+	}
4728c8
+	if (mpp->dev_loss > 600 &&
4728c8
+	    (mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF ||
4728c8
+             mpp->fast_io_fail == MP_FAST_IO_FAIL_UNSET)) {
4728c8
+		condlog(3, "%s: limiting dev_loss_tmo to 600, since "
4728c8
+			"fast_io_fail is unset or off", rport_id);
4728c8
+		mpp->dev_loss = 600;
4728c8
 	}
4728c8
-	if (mpp->fast_io_fail != MP_FAST_IO_FAIL_UNSET){
4728c8
+	if (mpp->fast_io_fail != MP_FAST_IO_FAIL_UNSET) {
4728c8
 		if (mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF)
4728c8
 			sprintf(value, "off");
4728c8
 		else if (mpp->fast_io_fail == MP_FAST_IO_FAIL_ZERO)
4728c8
 			sprintf(value, "0");
4728c8
+		else if (delay_fast_io_fail)
4728c8
+			snprintf(value, 16, "%u", current_dev_loss - 1);
4728c8
 		else
4728c8
-			snprintf(value, 11, "%u", mpp->fast_io_fail);
4728c8
-		if (sysfs_attr_set_value(rport_dev, "fast_io_fail_tmo",
4728c8
-					 value, 11) <= 0) {
4728c8
-			condlog(0, "%s failed to set fast_io_fail_tmo",
4728c8
-				mpp->alias);
4728c8
+			snprintf(value, 16, "%u", mpp->fast_io_fail);
4728c8
+		ret = sysfs_attr_set_value(rport_dev, "fast_io_fail_tmo",
4728c8
+					   value, strlen(value));
4728c8
+		if (ret <= 0) {
4728c8
+			if (ret == -EBUSY)
4728c8
+				condlog(3, "%s: rport blocked", rport_id);
4728c8
+			else
4728c8
+				condlog(0, "%s: failed to set fast_io_fail_tmo to %s, error %d",
4728c8
+					rport_id, value, -ret);
4728c8
+			goto out;
4728c8
+		}
4728c8
+	}
4728c8
+	if (mpp->dev_loss) {
4728c8
+		snprintf(value, 16, "%u", mpp->dev_loss);
4728c8
+		ret = sysfs_attr_set_value(rport_dev, "dev_loss_tmo",
4728c8
+					   value, strlen(value));
4728c8
+		if (ret <= 0) {
4728c8
+			if (ret == -EBUSY)
4728c8
+				condlog(3, "%s: rport blocked", rport_id);
4728c8
+			else
4728c8
+				condlog(0, "%s: failed to set dev_loss_tmo to %s, error %d",
4728c8
+					rport_id, value, -ret);
4728c8
+			goto out;
4728c8
+		}
4728c8
+	}
4728c8
+	if (delay_fast_io_fail) {
4728c8
+		snprintf(value, 16, "%u", mpp->fast_io_fail);
4728c8
+		ret = sysfs_attr_set_value(rport_dev, "fast_io_fail_tmo",
4728c8
+					   value, strlen(value));
4728c8
+		if (ret <= 0) {
4728c8
+			if (ret == -EBUSY)
4728c8
+				condlog(3, "%s: rport blocked", rport_id);
4728c8
+			else
4728c8
+				condlog(0, "%s: failed to set fast_io_fail_tmo to %s, error %d",
4728c8
+					rport_id, value, -ret);
4728c8
 		}
4728c8
 	}
4728c8
 out:
4728c8
@@ -394,7 +450,7 @@ sysfs_set_session_tmo(struct multipath *
4728c8
 		} else {
4728c8
 			snprintf(value, 11, "%u", mpp->fast_io_fail);
4728c8
 			if (sysfs_attr_set_value(session_dev, "recovery_tmo",
4728c8
-						 value, 11)) {
4728c8
+						 value, 11) <= 0) {
4728c8
 				condlog(3, "%s: Failed to set recovery_tmo, "
4728c8
 					" error %d", pp->dev, errno);
4728c8
 			}
4728c8
@@ -752,6 +808,9 @@ cciss_sysfs_pathinfo (struct path * pp)
4728c8
 static int
4728c8
 common_sysfs_pathinfo (struct path * pp)
4728c8
 {
4728c8
+	if (!pp)
4728c8
+		return 1;
4728c8
+
4728c8
 	if (!pp->udev) {
4728c8
 		condlog(4, "%s: udev not initialised", pp->dev);
4728c8
 		return 1;
4728c8
@@ -793,7 +852,8 @@ path_offline (struct path * pp)
4728c8
 		return PATH_DOWN;
4728c8
 	}
4728c8
 
4728c8
-	if (sysfs_get_state(parent, buff, SCSI_STATE_SIZE))
4728c8
+	memset(buff, 0x0, SCSI_STATE_SIZE);
4728c8
+	if (sysfs_attr_get_value(parent, "state", buff, SCSI_STATE_SIZE) <= 0)
4728c8
 		return PATH_DOWN;
4728c8
 
4728c8
 	condlog(3, "%s: path state = %s", pp->dev, buff);
4728c8
@@ -983,6 +1043,9 @@ pathinfo (struct path *pp, vector hwtabl
4728c8
 {
4728c8
 	int path_state;
4728c8
 
4728c8
+	if (!pp)
4728c8
+		return 1;
4728c8
+
4728c8
 	condlog(3, "%s: mask = 0x%x", pp->dev, mask);
4728c8
 
4728c8
 	/*
4728c8
Index: multipath-tools-130222/libmultipath/sysfs.c
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/libmultipath/sysfs.c
4728c8
+++ multipath-tools-130222/libmultipath/sysfs.c
4728c8
@@ -38,7 +38,12 @@
4728c8
 #include "debug.h"
4728c8
 #include "devmapper.h"
4728c8
 
4728c8
-ssize_t sysfs_attr_set_value(struct udev_device *dev, const char *attr_name,
4728c8
+/*
4728c8
+ * When we modify an attribute value we cannot rely on libudev for now,
4728c8
+ * as libudev lacks the capability to update an attribute value.
4728c8
+ * So for modified attributes we need to implement our own function.
4728c8
+ */
4728c8
+ssize_t sysfs_attr_get_value(struct udev_device *dev, const char *attr_name,
4728c8
 			     char * value, size_t value_len)
4728c8
 {
4728c8
 	char devpath[PATH_SIZE];
4728c8
@@ -54,28 +59,83 @@ ssize_t sysfs_attr_set_value(struct udev
4728c8
 	condlog(4, "open '%s'", devpath);
4728c8
 	if (stat(devpath, &statbuf) != 0) {
4728c8
 		condlog(4, "stat '%s' failed: %s", devpath, strerror(errno));
4728c8
-		return 0;
4728c8
+		return -errno;
4728c8
 	}
4728c8
 
4728c8
 	/* skip directories */
4728c8
-	if (S_ISDIR(statbuf.st_mode))
4728c8
-		return 0;
4728c8
+	if (S_ISDIR(statbuf.st_mode)) {
4728c8
+		condlog(4, "%s is a directory", devpath);
4728c8
+		return -EISDIR;
4728c8
+	}
4728c8
 
4728c8
 	/* skip non-writeable files */
4728c8
-	if ((statbuf.st_mode & S_IWUSR) == 0)
4728c8
+	if ((statbuf.st_mode & S_IRUSR) == 0) {
4728c8
+		condlog(4, "%s is not readable", devpath);
4728c8
+		return -EPERM;
4728c8
+	}
4728c8
+
4728c8
+	/* read attribute value */
4728c8
+	fd = open(devpath, O_RDONLY);
4728c8
+	if (fd < 0) {
4728c8
+		condlog(4, "attribute '%s' can not be opened: %s",
4728c8
+			devpath, strerror(errno));
4728c8
+		return -errno;
4728c8
+	}
4728c8
+	size = read(fd, value, value_len);
4728c8
+	if (size < 0) {
4728c8
+		condlog(4, "read from %s failed: %s", devpath, strerror(errno));
4728c8
+		size = -errno;
4728c8
+	} else if (size == value_len) {
4728c8
+		condlog(4, "overflow while reading from %s", devpath);
4728c8
+		size = 0;
4728c8
+	}
4728c8
+
4728c8
+	close(fd);
4728c8
+	return size;
4728c8
+}
4728c8
+
4728c8
+ssize_t sysfs_attr_set_value(struct udev_device *dev, const char *attr_name,
4728c8
+			     char * value, size_t value_len)
4728c8
+{
4728c8
+	char devpath[PATH_SIZE];
4728c8
+	struct stat statbuf;
4728c8
+	int fd;
4728c8
+	ssize_t size = -1;
4728c8
+
4728c8
+	if (!dev || !attr_name || !value || !value_len)
4728c8
 		return 0;
4728c8
 
4728c8
+	snprintf(devpath, PATH_SIZE, "%s/%s", udev_device_get_syspath(dev),
4728c8
+		 attr_name);
4728c8
+	condlog(4, "open '%s'", devpath);
4728c8
+	if (stat(devpath, &statbuf) != 0) {
4728c8
+		condlog(4, "stat '%s' failed: %s", devpath, strerror(errno));
4728c8
+		return -errno;
4728c8
+	}
4728c8
+
4728c8
+	/* skip directories */
4728c8
+	if (S_ISDIR(statbuf.st_mode)) {
4728c8
+		condlog(4, "%s is a directory", devpath);
4728c8
+		return -EISDIR;
4728c8
+	}
4728c8
+
4728c8
+	/* skip non-writeable files */
4728c8
+	if ((statbuf.st_mode & S_IWUSR) == 0) {
4728c8
+		condlog(4, "%s is not writeable", devpath);
4728c8
+		return -EPERM;
4728c8
+	}
4728c8
+
4728c8
 	/* write attribute value */
4728c8
 	fd = open(devpath, O_WRONLY);
4728c8
 	if (fd < 0) {
4728c8
 		condlog(4, "attribute '%s' can not be opened: %s",
4728c8
 			devpath, strerror(errno));
4728c8
-		return 0;
4728c8
+		return -errno;
4728c8
 	}
4728c8
 	size = write(fd, value, value_len);
4728c8
 	if (size < 0) {
4728c8
 		condlog(4, "write to %s failed: %s", devpath, strerror(errno));
4728c8
-		size = 0;
4728c8
+		size = -errno;
4728c8
 	} else if (size < value_len) {
4728c8
 		condlog(4, "tried to write %ld to %s. Wrote %ld",
4728c8
 			(long)value_len, devpath, (long)size);
4728c8
@@ -89,14 +149,14 @@ ssize_t sysfs_attr_set_value(struct udev
4728c8
 int
4728c8
 sysfs_get_size (struct path *pp, unsigned long long * size)
4728c8
 {
4728c8
-	const char * attr;
4728c8
+	char attr[255];
4728c8
 	int r;
4728c8
 
4728c8
-	if (!pp->udev)
4728c8
+	if (!pp->udev || !size)
4728c8
 		return 1;
4728c8
 
4728c8
-	attr = udev_device_get_sysattr_value(pp->udev, "size");
4728c8
-	if (!attr) {
4728c8
+	attr[0] = '\0';
4728c8
+	if (sysfs_attr_get_value(pp->udev, "size", attr, 255) == 0) {
4728c8
 		condlog(3, "%s: No size attribute in sysfs", pp->dev);
4728c8
 		return 1;
4728c8
 	}
4728c8
@@ -104,8 +164,8 @@ sysfs_get_size (struct path *pp, unsigne
4728c8
 	r = sscanf(attr, "%llu\n", size);
4728c8
 
4728c8
 	if (r != 1) {
4728c8
-		condlog(3, "%s: Cannot parse size attribute '%s'",
4728c8
-			pp->dev, attr);
4728c8
+		condlog(3, "%s: Cannot parse size attribute", pp->dev);
4728c8
+		*size = 0;
4728c8
 		return 1;
4728c8
 	}
4728c8
 
4728c8
Index: multipath-tools-130222/libmultipath/sysfs.h
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/libmultipath/sysfs.h
4728c8
+++ multipath-tools-130222/libmultipath/sysfs.h
4728c8
@@ -7,6 +7,8 @@
4728c8
 
4728c8
 ssize_t sysfs_attr_set_value(struct udev_device *dev, const char *attr_name,
4728c8
 			     char * value, size_t value_len);
4728c8
+ssize_t sysfs_attr_get_value(struct udev_device *dev, const char *attr_name,
4728c8
+			     char * value, size_t value_len);
4728c8
 int sysfs_get_size (struct path *pp, unsigned long long * size);
4728c8
 int sysfs_check_holders(char * check_devt, char * new_devt);
4728c8
 #endif