]> git.ipfire.org Git - people/stevee/ipfire-3.x.git/blobdiff - multipath-tools/patches/0057-UP-fix-tmo.patch
multipath-tools: Update to snapshot from 2013-02-22
[people/stevee/ipfire-3.x.git] / multipath-tools / patches / 0057-UP-fix-tmo.patch
diff --git a/multipath-tools/patches/0057-UP-fix-tmo.patch b/multipath-tools/patches/0057-UP-fix-tmo.patch
new file mode 100644 (file)
index 0000000..0bfc46b
--- /dev/null
@@ -0,0 +1,329 @@
+---
+ 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", &current_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