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