libmultipath/foreign/nvme: use failover topology
authorMartin Wilck <mwilck@suse.com>
Sun, 23 Dec 2018 22:21:23 +0000 (23:21 +0100)
committerChristophe Varoqui <christophe.varoqui@opensvc.com>
Mon, 7 Jan 2019 10:46:42 +0000 (11:46 +0100)
The native multipath driver does not use a multibus policy
as the current topology output of the NVMe foreign code
indicates. Rather, it uses failover policy, queueing all
IO to the current path until a failure occurs.

Change the data structures of the nvme foreign library
accordingly.

Signed-off-by: Martin Wilck <mwilck@suse.com>
libmultipath/foreign/nvme.c

index c753a74..1184988 100644 (file)
@@ -40,17 +40,22 @@ static const char N_A[] = "n/a";
 const char *THIS;
 
 struct nvme_map;
+struct nvme_pathgroup {
+       struct gen_pathgroup gen;
+       struct _vector pathvec;
+};
+
 struct nvme_path {
        struct gen_path gen;
        struct udev_device *udev;
        struct udev_device *ctl;
        struct nvme_map *map;
        bool seen;
-};
-
-struct nvme_pathgroup {
-       struct gen_pathgroup gen;
-       vector pathvec;
+       /*
+        * The kernel works in failover mode.
+        * Each path has a separate path group.
+        */
+       struct nvme_pathgroup pg;
 };
 
 struct nvme_map {
@@ -58,11 +63,7 @@ struct nvme_map {
        struct udev_device *udev;
        struct udev_device *subsys;
        dev_t devt;
-       /* Just one static pathgroup for NVMe for now */
-       struct nvme_pathgroup pg;
-       struct gen_pathgroup *gpg;
        struct _vector pgvec;
-       vector pathvec;
        int nr_live;
 };
 
@@ -76,29 +77,33 @@ struct nvme_map {
 #define const_gen_path_to_nvme(g) ((const struct nvme_path*)(g))
 #define gen_path_to_nvme(g) ((struct nvme_path*)(g))
 #define nvme_path_to_gen(n) &((n)->gen)
+#define nvme_pg_to_path(x) (VECTOR_SLOT(&((x)->pathvec), 0))
+#define nvme_path_to_pg(x) &((x)->pg)
 
 static void cleanup_nvme_path(struct nvme_path *path)
 {
        condlog(5, "%s: %p %p", __func__, path, path->udev);
        if (path->udev)
                udev_device_unref(path->udev);
+       vector_reset(&path->pg.pathvec);
+
        /* ctl is implicitly referenced by udev, no need to unref */
        free(path);
 }
 
 static void cleanup_nvme_map(struct nvme_map *map)
 {
-       if (map->pathvec) {
-               struct nvme_path *path;
-               int i;
+       struct nvme_pathgroup *pg;
+       struct nvme_path *path;
+       int i;
 
-               vector_foreach_slot_backwards(map->pathvec, path, i) {
-                       condlog(5, "%s: %d %p", __func__, i, path);
-                       cleanup_nvme_path(path);
-                       vector_del_slot(map->pathvec, i);
-               }
+       vector_foreach_slot_backwards(&map->pgvec, pg, i) {
+               path = nvme_pg_to_path(pg);
+               condlog(5, "%s: %d %p", __func__, i, path);
+               cleanup_nvme_path(path);
+               vector_del_slot(&map->pgvec, i);
        }
-       vector_free(map->pathvec);
+       vector_reset(&map->pgvec);
        if (map->udev)
                udev_device_unref(map->udev);
        /* subsys is implicitly referenced by udev, no need to unref */
@@ -190,7 +195,7 @@ nvme_pg_get_paths(const struct gen_pathgroup *gpg) {
        const struct nvme_pathgroup *gp = const_gen_pg_to_nvme(gpg);
 
        /* This is all used under the lock, no need to copy */
-       return gp->pathvec;
+       return &gp->pathvec;
 }
 
 static void
@@ -432,7 +437,7 @@ static struct nvme_map *_find_nvme_map_by_devt(const struct context *ctx,
 static struct nvme_path *
 _find_path_by_syspath(struct nvme_map *map, const char *syspath)
 {
-       struct nvme_path *path;
+       struct nvme_pathgroup *pg;
        char real[PATH_MAX];
        const char *ppath;
        int i;
@@ -443,7 +448,9 @@ _find_path_by_syspath(struct nvme_map *map, const char *syspath)
                ppath = syspath;
        }
 
-       vector_foreach_slot(map->pathvec, path, i) {
+       vector_foreach_slot(&map->pgvec, pg, i) {
+               struct nvme_path *path = nvme_pg_to_path(pg);
+
                if (!strcmp(ppath,
                            udev_device_get_syspath(path->udev)))
                        return path;
@@ -537,14 +544,17 @@ static void _find_controllers(struct context *ctx, struct nvme_map *map)
        struct dirent **di = NULL;
        struct scandir_result sr;
        struct udev_device *subsys;
+       struct nvme_pathgroup *pg;
        struct nvme_path *path;
        int r, i, n;
 
        if (map == NULL || map->udev == NULL)
                return;
 
-       vector_foreach_slot(map->pathvec, path, i)
+       vector_foreach_slot(&map->pgvec, pg, i) {
+               path = nvme_pg_to_path(pg);
                path->seen = false;
+       }
 
        subsys = udev_device_get_parent_with_subsystem_devtype(map->udev,
                                                               "nvme-subsystem",
@@ -606,7 +616,8 @@ static void _find_controllers(struct context *ctx, struct nvme_map *map)
                if (udev == NULL)
                        continue;
 
-               path = _find_path_by_syspath(map, udev_device_get_syspath(udev));
+               path = _find_path_by_syspath(map,
+                                            udev_device_get_syspath(udev));
                if (path != NULL) {
                        path->seen = true;
                        condlog(4, "%s: %s already known",
@@ -630,24 +641,30 @@ static void _find_controllers(struct context *ctx, struct nvme_map *map)
                        cleanup_nvme_path(path);
                        continue;
                }
-
-               if (vector_alloc_slot(map->pathvec) == NULL) {
+               path->pg.gen.ops = &nvme_pg_ops;
+               if (vector_alloc_slot(&path->pg.pathvec) == NULL) {
                        cleanup_nvme_path(path);
                        continue;
                }
+               vector_set_slot(&path->pg.pathvec, path);
+               if (vector_alloc_slot(&map->pgvec) == NULL) {
+                       cleanup_nvme_path(path);
+                       continue;
+               }
+               vector_set_slot(&map->pgvec, &path->pg);
                condlog(3, "%s: %s: new path %s added to %s",
                        __func__, THIS, udev_device_get_sysname(udev),
                        udev_device_get_sysname(map->udev));
-               vector_set_slot(map->pathvec, path);
        }
        pthread_cleanup_pop(1);
 
        map->nr_live = 0;
-       vector_foreach_slot_backwards(map->pathvec, path, i) {
+       vector_foreach_slot_backwards(&map->pgvec, pg, i) {
+               path = nvme_pg_to_path(pg);
                if (!path->seen) {
                        condlog(1, "path %d not found in %s any more",
                                i, udev_device_get_sysname(map->udev));
-                       vector_del_slot(map->pathvec, i);
+                       vector_del_slot(&map->pgvec, i);
                        cleanup_nvme_path(path);
                } else {
                        static const char live_state[] = "live";
@@ -661,7 +678,7 @@ static void _find_controllers(struct context *ctx, struct nvme_map *map)
        }
        condlog(3, "%s: %s: map %s has %d/%d live paths", __func__, THIS,
                udev_device_get_sysname(map->udev), map->nr_live,
-               VECTOR_SIZE(map->pathvec));
+               VECTOR_SIZE(&map->pgvec));
 }
 
 static int _add_map(struct context *ctx, struct udev_device *ud,
@@ -686,19 +703,6 @@ static int _add_map(struct context *ctx, struct udev_device *ud,
        map->subsys = subsys;
        map->gen.ops = &nvme_map_ops;
 
-       map->pathvec = vector_alloc();
-       if (map->pathvec == NULL) {
-               cleanup_nvme_map(map);
-               return FOREIGN_ERR;
-       }
-
-       map->pg.gen.ops = &nvme_pg_ops;
-       map->pg.pathvec = map->pathvec;
-       map->gpg = nvme_pg_to_gen(&map->pg);
-
-       map->pgvec.allocated = 1;
-       map->pgvec.slot = (void**)&map->gpg;
-
        if (vector_alloc_slot(ctx->mpvec) == NULL) {
                cleanup_nvme_map(map);
                return FOREIGN_ERR;
@@ -842,8 +846,8 @@ const struct _vector * get_paths(const struct context *ctx)
        condlog(5, "%s called for \"%s\"", __func__, THIS);
        vector_foreach_slot(ctx->mpvec, gm, i) {
                const struct nvme_map *nm = const_gen_mp_to_nvme(gm);
-               paths = vector_convert(paths, nm->pathvec,
-                                      struct gen_path, identity);
+               paths = vector_convert(paths, &nm->pgvec,
+                                      struct nvme_pathgroup, nvme_pg_to_path);
        }
        return paths;
 }