multipath: do not check daemon from udev rules
authorHannes Reinecke <hare@suse.de>
Tue, 28 Feb 2017 16:23:00 +0000 (17:23 +0100)
committerChristophe Varoqui <christophe.varoqui@opensvc.com>
Thu, 16 Mar 2017 06:57:16 +0000 (07:57 +0100)
As stated previously, multipathd needs to start after udev trigger
has run as otherwise it won't be able to find any devices.
However, this also means that during udevadm trigger the daemon
wouldn't run, and consequently the check in the udev rules will
always be false, causing the device not to be marked as multipath
capable.

As it turns out, calling 'multipath' from udev rules has quite some
challenges. It _should_ check if a device is eligible for multipathing.
But it needs to work under all circumstances, even if the daemon isn't
running yet, as the program will be called from uevents which might
(and will) come in before the daemon is running.
To check if the daemon _should_ be run I'm checking the various
'.wants' directories from systemd, which carries links to the services
systemd will enable eventually. So if the multipathd.service is
listed in there it will be started, even if it isn't started yet.

Signed-off-by: Hannes Reinecke <hare@suse.com>
libmultipath/util.c
libmultipath/util.h
multipath/main.c

index 85d21fa..b90cd8b 100644 (file)
@@ -6,13 +6,16 @@
 #include <sys/stat.h>
 #include <sys/sysmacros.h>
 #include <sys/types.h>
+#include <dirent.h>
 #include <unistd.h>
+#include <errno.h>
 
 #include "debug.h"
 #include "memory.h"
 #include "checkers.h"
 #include "vector.h"
 #include "structs.h"
+#include "log.h"
 
 size_t
 strchop(char *str)
@@ -321,3 +324,59 @@ setup_thread_attr(pthread_attr_t *attr, size_t stacksize, int detached)
                assert(ret == 0);
        }
 }
+
+int systemd_service_enabled_in(const char *dev, const char *prefix)
+{
+       char path[PATH_SIZE], file[PATH_SIZE], service[PATH_SIZE];
+       DIR *dirfd;
+       struct dirent *d;
+       int found = 0;
+
+       snprintf(service, PATH_SIZE, "multipathd.service");
+       snprintf(path, PATH_SIZE, "%s/systemd/system", prefix);
+       condlog(3, "%s: checking for %s in %s", dev, service, path);
+
+       dirfd = opendir(path);
+       if (dirfd == NULL)
+               return 0;
+
+       while ((d = readdir(dirfd)) != NULL) {
+               char *p;
+               struct stat stbuf;
+
+               if ((strcmp(d->d_name,".") == 0) ||
+                   (strcmp(d->d_name,"..") == 0))
+                       continue;
+
+               if (strlen(d->d_name) < 6)
+                       continue;
+
+               p = d->d_name + strlen(d->d_name) - 6;
+               if (strcmp(p, ".wants"))
+                       continue;
+               snprintf(file, PATH_SIZE, "%s/%s/%s",
+                        path, d->d_name, service);
+               if (stat(file, &stbuf) == 0) {
+                       condlog(3, "%s: found %s", dev, file);
+                       found++;
+                       break;
+               }
+       }
+       closedir(dirfd);
+
+       return found;
+}
+
+int systemd_service_enabled(const char *dev)
+{
+       int found = 0;
+
+       found = systemd_service_enabled_in(dev, "/etc");
+       if (!found)
+               found = systemd_service_enabled_in(dev, "/usr/lib");
+       if (!found)
+               found = systemd_service_enabled_in(dev, "/lib");
+       if (!found)
+               found = systemd_service_enabled_in(dev, "/run");
+       return found;
+}
index 793f2b7..b087e32 100644 (file)
@@ -14,6 +14,7 @@ dev_t parse_devt(const char *dev_t);
 char *convert_dev(char *dev, int is_path_device);
 char *parse_uid_attribute_by_attrs(char *uid_attrs, char *path_dev);
 void setup_thread_attr(pthread_attr_t *attr, size_t stacksize, int detached);
+int systemd_service_enabled(const char *dev);
 
 #define safe_sprintf(var, format, args...)     \
        snprintf(var, sizeof(var), format, ##args) >= sizeof(var)
index 171c08b..befe4c5 100644 (file)
@@ -682,11 +682,14 @@ main (int argc, char *argv[])
 
                fd = mpath_connect();
                if (fd == -1) {
-                       printf("%s is not a valid multipath device path\n",
-                               dev);
-                       goto out;
-               }
-               mpath_disconnect(fd);
+                       condlog(3, "%s: daemon is not running", dev);
+                       if (!systemd_service_enabled(dev)) {
+                               printf("%s is not a valid "
+                                      "multipath device path\n", dev);
+                               goto out;
+                       }
+               } else
+                       mpath_disconnect(fd);
        }
        if (cmd == CMD_REMOVE_WWID && !dev) {
                condlog(0, "the -w option requires a device");