Imported Upstream version 0.8.7
[platform/upstream/multipath-tools.git] / libmultipath / foreign / nvme.c
1 /*
2   Copyright (c) 2018 Martin Wilck, SUSE Linux GmbH
3
4   This program is free software; you can redistribute it and/or
5   modify it under the terms of the GNU General Public License
6   as published by the Free Software Foundation; either version 2
7   of the License, or (at your option) any later version.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13
14   You should have received a copy of the GNU General Public License
15   along with this program.  If not, see <https://www.gnu.org/licenses/>.
16 */
17
18 #include "nvme-lib.h"
19 #include <sys/types.h>
20 #include <sys/sysmacros.h>
21 #include <libudev.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdbool.h>
26 #include <libudev.h>
27 #include <pthread.h>
28 #include <limits.h>
29 #include <dirent.h>
30 #include <errno.h>
31 #include <ctype.h>
32 #include <fcntl.h>
33 #include "util.h"
34 #include "vector.h"
35 #include "generic.h"
36 #include "foreign.h"
37 #include "debug.h"
38 #include "structs.h"
39 #include "sysfs.h"
40 #include "strbuf.h"
41
42 static const char nvme_vendor[] = "NVMe";
43 static const char N_A[] = "n/a";
44 const char *THIS;
45
46 struct nvme_map;
47 struct nvme_pathgroup {
48         struct gen_pathgroup gen;
49         struct _vector pathvec;
50 };
51
52 struct nvme_path {
53         struct gen_path gen;
54         struct udev_device *udev;
55         struct udev_device *ctl;
56         struct nvme_map *map;
57         bool seen;
58         /*
59          * The kernel works in failover mode.
60          * Each path has a separate path group.
61          */
62         struct nvme_pathgroup pg;
63 };
64
65 struct nvme_map {
66         struct gen_multipath gen;
67         struct udev_device *udev;
68         struct udev_device *subsys;
69         dev_t devt;
70         struct _vector pgvec;
71         int nr_live;
72         int ana_supported;
73 };
74
75 #define NAME_LEN 64 /* buffer length for temp attributes */
76 #define const_gen_mp_to_nvme(g) ((const struct nvme_map*)(g))
77 #define gen_mp_to_nvme(g) ((struct nvme_map*)(g))
78 #define nvme_mp_to_gen(n) &((n)->gen)
79 #define const_gen_pg_to_nvme(g) ((const struct nvme_pathgroup*)(g))
80 #define gen_pg_to_nvme(g) ((struct nvme_pathgroup*)(g))
81 #define nvme_pg_to_gen(n) &((n)->gen)
82 #define const_gen_path_to_nvme(g) ((const struct nvme_path*)(g))
83 #define gen_path_to_nvme(g) ((struct nvme_path*)(g))
84 #define nvme_path_to_gen(n) &((n)->gen)
85 #define nvme_pg_to_path(x) (VECTOR_SLOT(&((x)->pathvec), 0))
86 #define nvme_path_to_pg(x) &((x)->pg)
87
88 static void cleanup_nvme_path(struct nvme_path *path)
89 {
90         condlog(5, "%s: %p %p", __func__, path, path->udev);
91         if (path->udev)
92                 udev_device_unref(path->udev);
93         vector_reset(&path->pg.pathvec);
94
95         /* ctl is implicitly referenced by udev, no need to unref */
96         free(path);
97 }
98
99 static void cleanup_nvme_map(struct nvme_map *map)
100 {
101         struct nvme_pathgroup *pg;
102         struct nvme_path *path;
103         int i;
104
105         vector_foreach_slot_backwards(&map->pgvec, pg, i) {
106                 path = nvme_pg_to_path(pg);
107                 condlog(5, "%s: %d %p", __func__, i, path);
108                 cleanup_nvme_path(path);
109                 vector_del_slot(&map->pgvec, i);
110         }
111         vector_reset(&map->pgvec);
112         if (map->udev)
113                 udev_device_unref(map->udev);
114         /* subsys is implicitly referenced by udev, no need to unref */
115         free(map);
116 }
117
118 static const struct _vector*
119 nvme_mp_get_pgs(const struct gen_multipath *gmp) {
120         const struct nvme_map *nvme = const_gen_mp_to_nvme(gmp);
121
122         /* This is all used under the lock, no need to copy */
123         return &nvme->pgvec;
124 }
125
126 static void
127 nvme_mp_rel_pgs(__attribute__((unused)) const struct gen_multipath *gmp,
128                 __attribute__((unused)) const struct _vector *v)
129 {
130         /* empty */
131 }
132
133 static void rstrip(char *str)
134 {
135         int n;
136
137         for (n = strlen(str) - 1; n >= 0 && str[n] == ' '; n--);
138         str[n+1] = '\0';
139 }
140
141 static int snprint_nvme_map(const struct gen_multipath *gmp,
142                             struct strbuf *buff, char wildcard)
143 {
144         const struct nvme_map *nvm = const_gen_mp_to_nvme(gmp);
145         char fld[NAME_LEN];
146         const char *val;
147
148         switch (wildcard) {
149         case 'd':
150                 return append_strbuf_str(buff,
151                                 udev_device_get_sysname(nvm->udev));
152         case 'n':
153                 return print_strbuf(buff, "%s:nsid.%s",
154                                 udev_device_get_sysattr_value(nvm->subsys,
155                                                               "subsysnqn"),
156                                 udev_device_get_sysattr_value(nvm->udev,
157                                                               "nsid"));
158         case 'w':
159                 return append_strbuf_str(buff,
160                                 udev_device_get_sysattr_value(nvm->udev,
161                                                               "wwid"));
162         case 'N':
163                 return print_strbuf(buff, "%u", nvm->nr_live);
164         case 'S':
165                 return append_strbuf_str(buff,
166                                 udev_device_get_sysattr_value(nvm->udev,
167                                                               "size"));
168         case 'v':
169                 return append_strbuf_str(buff, nvme_vendor);
170         case 's':
171         case 'p':
172                 snprintf(fld, sizeof(fld), "%s",
173                          udev_device_get_sysattr_value(nvm->subsys,
174                                                       "model"));
175                 rstrip(fld);
176                 if (wildcard == 'p')
177                         return append_strbuf_str(buff, fld);
178                 return print_strbuf(buff, "%s,%s,%s", nvme_vendor, fld,
179                                 udev_device_get_sysattr_value(nvm->subsys,
180                                                               "firmware_rev"));
181         case 'e':
182                 return append_strbuf_str(buff,
183                                 udev_device_get_sysattr_value(nvm->subsys,
184                                                               "firmware_rev"));
185         case 'r':
186                 val = udev_device_get_sysattr_value(nvm->udev, "ro");
187                 if (val[0] == 1)
188                         return append_strbuf_str(buff, "ro");
189                 else
190                         return append_strbuf_str(buff, "rw");
191         case 'G':
192                 return append_strbuf_str(buff, THIS);
193         case 'h':
194                 if (nvm->ana_supported == YNU_YES)
195                         return append_strbuf_str(buff, "ANA");
196         default:
197                 break;
198         }
199
200         return append_strbuf_str(buff, N_A);
201 }
202
203 static const struct _vector*
204 nvme_pg_get_paths(const struct gen_pathgroup *gpg) {
205         const struct nvme_pathgroup *gp = const_gen_pg_to_nvme(gpg);
206
207         /* This is all used under the lock, no need to copy */
208         return &gp->pathvec;
209 }
210
211 static void
212 nvme_pg_rel_paths(__attribute__((unused)) const struct gen_pathgroup *gpg,
213                   __attribute__((unused)) const struct _vector *v)
214 {
215         /* empty */
216 }
217
218 static int snprint_hcil(const struct nvme_path *np, struct strbuf *buf)
219 {
220         unsigned int nvmeid, ctlid, nsid;
221         int rc;
222         const char *sysname = udev_device_get_sysname(np->udev);
223
224         rc = sscanf(sysname, "nvme%uc%un%u", &nvmeid, &ctlid, &nsid);
225         if (rc != 3) {
226                 condlog(1, "%s: failed to scan %s", __func__, sysname);
227                 return print_strbuf(buf, "(ERR:%s)", sysname);
228         } else
229                 return print_strbuf(buf, "%u:%u:%u", nvmeid, ctlid, nsid);
230 }
231
232 static int snprint_nvme_path(const struct gen_path *gp,
233                              struct strbuf *buff, char wildcard)
234 {
235         const struct nvme_path *np = const_gen_path_to_nvme(gp);
236         dev_t devt;
237         char fld[NAME_LEN];
238         struct udev_device *pci;
239
240         switch (wildcard) {
241         case 'w':
242                 return print_strbuf(buff, "%s",
243                                     udev_device_get_sysattr_value(np->udev,
244                                                                   "wwid"));
245         case 'd':
246                 return print_strbuf(buff, "%s",
247                                     udev_device_get_sysname(np->udev));
248         case 'i':
249                 return snprint_hcil(np, buff);
250         case 'D':
251                 devt = udev_device_get_devnum(np->udev);
252                 return print_strbuf(buff, "%u:%u", major(devt), minor(devt));
253         case 'o':
254                 if (sysfs_attr_get_value(np->ctl, "state",
255                                          fld, sizeof(fld)) > 0)
256                         return append_strbuf_str(buff, fld);
257                 break;
258         case 'T':
259                 if (sysfs_attr_get_value(np->udev, "ana_state", fld,
260                                          sizeof(fld)) > 0)
261                         return append_strbuf_str(buff, fld);
262                 break;
263         case 'p':
264                 if (sysfs_attr_get_value(np->udev, "ana_state", fld,
265                                          sizeof(fld)) > 0) {
266                         rstrip(fld);
267                         if (!strcmp(fld, "optimized"))
268                                 return print_strbuf(buff, "%d", 50);
269                         else if (!strcmp(fld, "non-optimized"))
270                                 return print_strbuf(buff, "%d", 10);
271                         else
272                                 return print_strbuf(buff, "%d", 0);
273                 }
274                 break;
275         case 's':
276                 snprintf(fld, sizeof(fld), "%s",
277                          udev_device_get_sysattr_value(np->ctl,
278                                                       "model"));
279                 rstrip(fld);
280                 return print_strbuf(buff, "%s,%s,%s", nvme_vendor, fld,
281                                     udev_device_get_sysattr_value(np->ctl,
282                                                               "firmware_rev"));
283         case 'S':
284                 return append_strbuf_str(buff,
285                         udev_device_get_sysattr_value(np->udev,
286                                                       "size"));
287         case 'z':
288                 return append_strbuf_str(buff,
289                                 udev_device_get_sysattr_value(np->ctl,
290                                                               "serial"));
291         case 'm':
292                 return append_strbuf_str(buff,
293                                 udev_device_get_sysname(np->map->udev));
294         case 'N':
295         case 'R':
296                 return print_strbuf(buff, "%s:%s",
297                         udev_device_get_sysattr_value(np->ctl,
298                                                       "transport"),
299                         udev_device_get_sysattr_value(np->ctl,
300                                                       "address"));
301         case 'G':
302                 return print_strbuf(buff, "[%s]", THIS);
303         case 'a':
304                 pci = udev_device_get_parent_with_subsystem_devtype(np->ctl,
305                                                                     "pci",
306                                                                     NULL);
307                 if (pci != NULL)
308                         return print_strbuf(buff, "PCI:%s",
309                                             udev_device_get_sysname(pci));
310                 /* fall through */
311         default:
312                 break;
313         }
314         return append_strbuf_str(buff, N_A);
315 }
316
317 static int snprint_nvme_pg(const struct gen_pathgroup *gmp,
318                            struct strbuf *buff, char wildcard)
319 {
320         const struct nvme_pathgroup *pg = const_gen_pg_to_nvme(gmp);
321         const struct nvme_path *path = nvme_pg_to_path(pg);
322
323         switch (wildcard) {
324         case 't':
325                 return snprint_nvme_path(nvme_path_to_gen(path),
326                                          buff, 'T');
327         case 'p':
328                 return snprint_nvme_path(nvme_path_to_gen(path),
329                                          buff, 'p');
330         default:
331                 return append_strbuf_str(buff, N_A);
332         }
333 }
334
335 static int nvme_style(__attribute__((unused)) const struct gen_multipath* gm,
336                       struct strbuf *buf, __attribute__((unused)) int verbosity)
337 {
338         return append_strbuf_str(buf, "%%w [%%G]:%%d %%s");
339 }
340
341 static const struct gen_multipath_ops nvme_map_ops = {
342         .get_pathgroups = nvme_mp_get_pgs,
343         .rel_pathgroups = nvme_mp_rel_pgs,
344         .style = nvme_style,
345         .snprint = snprint_nvme_map,
346 };
347
348 static const struct gen_pathgroup_ops nvme_pg_ops __attribute__((unused)) = {
349         .get_paths = nvme_pg_get_paths,
350         .rel_paths = nvme_pg_rel_paths,
351         .snprint = snprint_nvme_pg,
352 };
353
354 static const struct gen_path_ops nvme_path_ops __attribute__((unused)) = {
355         .snprint = snprint_nvme_path,
356 };
357
358 struct context {
359         pthread_mutex_t mutex;
360         vector mpvec;
361         struct udev *udev;
362 };
363
364 void lock(struct context *ctx)
365 {
366         pthread_mutex_lock(&ctx->mutex);
367 }
368
369 void unlock(void *arg)
370 {
371         struct context *ctx = arg;
372
373         pthread_mutex_unlock(&ctx->mutex);
374 }
375
376 static int _delete_all(struct context *ctx)
377 {
378         struct nvme_map *nm;
379         int n = VECTOR_SIZE(ctx->mpvec), i;
380
381         if (n == 0)
382                 return FOREIGN_IGNORED;
383
384         vector_foreach_slot_backwards(ctx->mpvec, nm, i) {
385                 vector_del_slot(ctx->mpvec, i);
386                 cleanup_nvme_map(nm);
387         }
388         return FOREIGN_OK;
389 }
390
391 int delete_all(struct context *ctx)
392 {
393         int rc;
394
395         condlog(5, "%s called for \"%s\"", __func__, THIS);
396
397         lock(ctx);
398         pthread_cleanup_push(unlock, ctx);
399         rc = _delete_all(ctx);
400         pthread_cleanup_pop(1);
401
402         return rc;
403 }
404
405 void cleanup(struct context *ctx)
406 {
407         (void)delete_all(ctx);
408
409         lock(ctx);
410         /*
411          * Locking is not strictly necessary here, locking in foreign.c
412          * makes sure that no other code is called with this ctx any more.
413          * But this should make static checkers feel better.
414          */
415         pthread_cleanup_push(unlock, ctx);
416         if (ctx->udev)
417                 udev_unref(ctx->udev);
418         if (ctx->mpvec)
419                 vector_free(ctx->mpvec);
420         ctx->mpvec = NULL;
421         ctx->udev = NULL;
422         pthread_cleanup_pop(1);
423         pthread_mutex_destroy(&ctx->mutex);
424
425         free(ctx);
426 }
427
428 struct context *init(unsigned int api, const char *name)
429 {
430         struct context *ctx;
431
432         if (api > LIBMP_FOREIGN_API) {
433                 condlog(0, "%s: api version mismatch: %08x > %08x\n",
434                         __func__, api, LIBMP_FOREIGN_API);
435                 return NULL;
436         }
437
438         if ((ctx = calloc(1, sizeof(*ctx)))== NULL)
439                 return NULL;
440
441         pthread_mutex_init(&ctx->mutex, NULL);
442
443         ctx->udev = udev_new();
444         if (ctx->udev == NULL)
445                 goto err;
446
447         ctx->mpvec = vector_alloc();
448         if (ctx->mpvec == NULL)
449                 goto err;
450
451         THIS = name;
452         return ctx;
453 err:
454         cleanup(ctx);
455         return NULL;
456 }
457
458 static struct nvme_map *_find_nvme_map_by_devt(const struct context *ctx,
459                                               dev_t devt)
460 {
461         struct nvme_map *nm;
462         int i;
463
464         if (ctx->mpvec == NULL)
465                 return NULL;
466
467         vector_foreach_slot(ctx->mpvec, nm, i) {
468                 if (nm->devt == devt)
469                         return nm;
470         }
471
472         return NULL;
473 }
474
475 static struct nvme_path *
476 _find_path_by_syspath(struct nvme_map *map, const char *syspath)
477 {
478         struct nvme_pathgroup *pg;
479         char real[PATH_MAX];
480         const char *ppath;
481         const char *psyspath;
482         int i;
483
484         ppath = realpath(syspath, real);
485         if (ppath == NULL) {
486                 condlog(1, "%s: %s: error in realpath", __func__, THIS);
487                 ppath = syspath;
488         }
489
490         vector_foreach_slot(&map->pgvec, pg, i) {
491                 struct nvme_path *path = nvme_pg_to_path(pg);
492
493                 psyspath = udev_device_get_syspath(path->udev);
494                 if (psyspath && !strcmp(ppath, psyspath))
495                         return path;
496         }
497         condlog(4, "%s: %s: %s not found", __func__, THIS, ppath);
498         return NULL;
499 }
500
501 static void _udev_device_unref(void *p)
502 {
503         udev_device_unref(p);
504 }
505
506 static void _udev_enumerate_unref(void *p)
507 {
508         udev_enumerate_unref(p);
509 }
510
511 static int _dirent_controller(const struct dirent *di)
512 {
513         static const char nvme_prefix[] = "nvme";
514         const char *p;
515
516 #ifdef _DIRENT_HAVE_D_TYPE
517         if (di->d_type != DT_LNK)
518                 return 0;
519 #endif
520         if (strncmp(di->d_name, nvme_prefix, sizeof(nvme_prefix) - 1))
521                 return 0;
522         p = di->d_name + sizeof(nvme_prefix) - 1;
523         if (*p == '\0' || !isdigit(*p))
524                 return 0;
525         for (++p; *p != '\0'; ++p)
526                 if (!isdigit(*p))
527                         return 0;
528         return 1;
529 }
530
531 /* Find the block device for a given nvme controller */
532 struct udev_device *get_ctrl_blkdev(const struct context *ctx,
533                                     struct udev_device *ctrl)
534 {
535         struct udev_list_entry *item;
536         struct udev_device *blkdev = NULL;
537         struct udev_enumerate *enm = udev_enumerate_new(ctx->udev);
538         const char *devtype;
539
540         if (enm == NULL)
541                 return NULL;
542
543         pthread_cleanup_push(_udev_enumerate_unref, enm);
544         if (udev_enumerate_add_match_parent(enm, ctrl) < 0)
545                 goto out;
546         if (udev_enumerate_add_match_subsystem(enm, "block"))
547                 goto out;
548
549         if (udev_enumerate_scan_devices(enm) < 0) {
550                 condlog(1, "%s: %s: error enumerating devices", __func__, THIS);
551                 goto out;
552         }
553
554         for (item = udev_enumerate_get_list_entry(enm);
555              item != NULL;
556              item = udev_list_entry_get_next(item)) {
557                 struct udev_device *tmp;
558
559                 tmp = udev_device_new_from_syspath(ctx->udev,
560                                            udev_list_entry_get_name(item));
561                 if (tmp == NULL)
562                         continue;
563
564                 devtype = udev_device_get_devtype(tmp);
565                 if (devtype && !strcmp(devtype, "disk")) {
566                         blkdev = tmp;
567                         break;
568                 } else
569                         udev_device_unref(tmp);
570         }
571
572         if (blkdev == NULL)
573                 condlog(1, "%s: %s: failed to get blockdev for %s",
574                         __func__, THIS, udev_device_get_sysname(ctrl));
575         else
576                 condlog(5, "%s: %s: got %s", __func__, THIS,
577                         udev_device_get_sysname(blkdev));
578 out:
579         pthread_cleanup_pop(1);
580         return blkdev;
581 }
582
583 static void test_ana_support(struct nvme_map *map, struct udev_device *ctl)
584 {
585         const char *dev_t;
586         char sys_path[64];
587         long fd;
588         int rc;
589
590         if (map->ana_supported != YNU_UNDEF)
591                 return;
592
593         dev_t = udev_device_get_sysattr_value(ctl, "dev");
594         if (safe_sprintf(sys_path, "/dev/char/%s", dev_t))
595                 return;
596
597         fd = open(sys_path, O_RDONLY);
598         if (fd == -1) {
599                 condlog(2, "%s: error opening %s", __func__, sys_path);
600                 return;
601         }
602
603         pthread_cleanup_push(close_fd, (void *)fd);
604         rc = nvme_id_ctrl_ana(fd, NULL);
605         if (rc < 0)
606                 condlog(2, "%s: error in nvme_id_ctrl: %s", __func__,
607                         strerror(errno));
608         else {
609                 map->ana_supported = (rc == 1 ? YNU_YES : YNU_NO);
610                 condlog(3, "%s: NVMe ctrl %s: ANA %s supported", __func__, dev_t,
611                         rc == 1 ? "is" : "is not");
612         }
613         pthread_cleanup_pop(1);
614 }
615
616 static void _find_controllers(struct context *ctx, struct nvme_map *map)
617 {
618         char pathbuf[PATH_MAX], realbuf[PATH_MAX];
619         struct dirent **di = NULL;
620         struct scandir_result sr;
621         struct udev_device *subsys;
622         struct nvme_pathgroup *pg;
623         struct nvme_path *path;
624         int r, i, n;
625
626         if (map == NULL || map->udev == NULL)
627                 return;
628
629         vector_foreach_slot(&map->pgvec, pg, i) {
630                 path = nvme_pg_to_path(pg);
631                 path->seen = false;
632         }
633
634         subsys = udev_device_get_parent_with_subsystem_devtype(map->udev,
635                                                                "nvme-subsystem",
636                                                                NULL);
637         if (subsys == NULL) {
638                 condlog(1, "%s: %s: BUG: no NVME subsys for %s", __func__, THIS,
639                         udev_device_get_sysname(map->udev));
640                 return;
641         }
642
643         n = snprintf(pathbuf, sizeof(pathbuf), "%s",
644                      udev_device_get_syspath(subsys));
645         r = scandir(pathbuf, &di, _dirent_controller, alphasort);
646
647         if (r == 0) {
648                 condlog(3, "%s: %s: no controllers for %s", __func__, THIS,
649                         udev_device_get_sysname(map->udev));
650                 return;
651         } else if (r < 0) {
652                 condlog(1, "%s: %s: error %d scanning controllers of %s",
653                         __func__, THIS, errno,
654                         udev_device_get_sysname(map->udev));
655                 return;
656         }
657
658         sr.di = di;
659         sr.n = r;
660         pthread_cleanup_push_cast(free_scandir_result, &sr);
661         for (i = 0; i < r; i++) {
662                 char *fn = di[i]->d_name;
663                 struct udev_device *ctrl, *udev;
664
665                 if (safe_snprintf(pathbuf + n, sizeof(pathbuf) - n, "/%s", fn))
666                         continue;
667                 if (realpath(pathbuf, realbuf) == NULL) {
668                         condlog(3, "%s: %s: realpath: %s", __func__, THIS,
669                                 strerror(errno));
670                         continue;
671                 }
672                 condlog(4, "%s: %s: found %s", __func__, THIS, realbuf);
673
674                 ctrl = udev_device_new_from_syspath(ctx->udev, realbuf);
675                 if (ctrl == NULL) {
676                         condlog(1, "%s: %s: failed to get udev device for %s",
677                                 __func__, THIS, realbuf);
678                         continue;
679                 }
680
681                 pthread_cleanup_push(_udev_device_unref, ctrl);
682                 udev = get_ctrl_blkdev(ctx, ctrl);
683                 /*
684                  * We give up the reference to the nvme device here and get
685                  * it back from the child below.
686                  * This way we don't need to worry about unreffing it.
687                  */
688                 pthread_cleanup_pop(1);
689
690                 if (udev == NULL)
691                         continue;
692
693                 path = _find_path_by_syspath(map,
694                                              udev_device_get_syspath(udev));
695                 if (path != NULL) {
696                         path->seen = true;
697                         condlog(4, "%s: %s already known",
698                                 __func__, fn);
699                         continue;
700                 }
701
702                 path = calloc(1, sizeof(*path));
703                 if (path == NULL)
704                         continue;
705
706                 path->gen.ops = &nvme_path_ops;
707                 path->udev = udev;
708                 path->seen = true;
709                 path->map = map;
710                 path->ctl = udev_device_get_parent_with_subsystem_devtype
711                         (udev, "nvme", NULL);
712                 if (path->ctl == NULL) {
713                         condlog(1, "%s: %s: failed to get controller for %s",
714                                 __func__, THIS, fn);
715                         cleanup_nvme_path(path);
716                         continue;
717                 }
718                 test_ana_support(map, path->ctl);
719
720                 path->pg.gen.ops = &nvme_pg_ops;
721                 if (!vector_alloc_slot(&path->pg.pathvec)) {
722                         cleanup_nvme_path(path);
723                         continue;
724                 }
725                 vector_set_slot(&path->pg.pathvec, path);
726                 if (!vector_alloc_slot(&map->pgvec)) {
727                         cleanup_nvme_path(path);
728                         continue;
729                 }
730                 vector_set_slot(&map->pgvec, &path->pg);
731                 condlog(3, "%s: %s: new path %s added to %s",
732                         __func__, THIS, udev_device_get_sysname(udev),
733                         udev_device_get_sysname(map->udev));
734         }
735         pthread_cleanup_pop(1);
736
737         map->nr_live = 0;
738         vector_foreach_slot_backwards(&map->pgvec, pg, i) {
739                 path = nvme_pg_to_path(pg);
740                 if (!path->seen) {
741                         condlog(1, "path %d not found in %s any more",
742                                 i, udev_device_get_sysname(map->udev));
743                         vector_del_slot(&map->pgvec, i);
744                         cleanup_nvme_path(path);
745                 } else {
746                         static const char live_state[] = "live";
747                         char state[16];
748
749                         if ((sysfs_attr_get_value(path->ctl, "state", state,
750                                                   sizeof(state)) > 0) &&
751                             !strncmp(state, live_state, sizeof(live_state) - 1))
752                                 map->nr_live++;
753                 }
754         }
755         condlog(3, "%s: %s: map %s has %d/%d live paths", __func__, THIS,
756                 udev_device_get_sysname(map->udev), map->nr_live,
757                 VECTOR_SIZE(&map->pgvec));
758 }
759
760 static int _add_map(struct context *ctx, struct udev_device *ud,
761                     struct udev_device *subsys)
762 {
763         dev_t devt = udev_device_get_devnum(ud);
764         struct nvme_map *map;
765
766         if (_find_nvme_map_by_devt(ctx, devt) != NULL)
767                 return FOREIGN_OK;
768
769         map = calloc(1, sizeof(*map));
770         if (map == NULL)
771                 return FOREIGN_ERR;
772
773         map->devt = devt;
774         map->udev = udev_device_ref(ud);
775         /*
776          * subsys is implicitly referenced by map->udev,
777          * no need to take a reference here.
778          */
779         map->subsys = subsys;
780         map->gen.ops = &nvme_map_ops;
781
782         if (!vector_alloc_slot(ctx->mpvec)) {
783                 cleanup_nvme_map(map);
784                 return FOREIGN_ERR;
785         }
786         vector_set_slot(ctx->mpvec, map);
787         _find_controllers(ctx, map);
788
789         return FOREIGN_CLAIMED;
790 }
791
792 int add(struct context *ctx, struct udev_device *ud)
793 {
794         struct udev_device *subsys;
795         int rc;
796         const char *devtype;
797
798         condlog(5, "%s called for \"%s\"", __func__, THIS);
799
800         if (ud == NULL)
801                 return FOREIGN_ERR;
802         if ((devtype = udev_device_get_devtype(ud)) == NULL ||
803                                                 strcmp("disk", devtype))
804                 return FOREIGN_IGNORED;
805
806         subsys = udev_device_get_parent_with_subsystem_devtype(ud,
807                                                                "nvme-subsystem",
808                                                                NULL);
809         if (subsys == NULL)
810                 return FOREIGN_IGNORED;
811
812         lock(ctx);
813         pthread_cleanup_push(unlock, ctx);
814         rc = _add_map(ctx, ud, subsys);
815         pthread_cleanup_pop(1);
816
817         if (rc == FOREIGN_CLAIMED)
818                 condlog(3, "%s: %s: added map %s", __func__, THIS,
819                         udev_device_get_sysname(ud));
820         else if (rc != FOREIGN_OK)
821                 condlog(1, "%s: %s: retcode %d adding %s",
822                         __func__, THIS, rc, udev_device_get_sysname(ud));
823
824         return rc;
825 }
826
827 int change(__attribute__((unused)) struct context *ctx,
828            __attribute__((unused)) struct udev_device *ud)
829 {
830         condlog(5, "%s called for \"%s\"", __func__, THIS);
831         return FOREIGN_IGNORED;
832 }
833
834 static int _delete_map(struct context *ctx, struct udev_device *ud)
835 {
836         int k;
837         struct nvme_map *map;
838         dev_t devt = udev_device_get_devnum(ud);
839
840         map = _find_nvme_map_by_devt(ctx, devt);
841         if (map ==NULL)
842                 return FOREIGN_IGNORED;
843
844         k = find_slot(ctx->mpvec, map);
845         if (k == -1)
846                 return FOREIGN_ERR;
847         else
848                 vector_del_slot(ctx->mpvec, k);
849
850         cleanup_nvme_map(map);
851
852         return FOREIGN_OK;
853 }
854
855 int delete(struct context *ctx, struct udev_device *ud)
856 {
857         int rc;
858
859         condlog(5, "%s called for \"%s\"", __func__, THIS);
860
861         if (ud == NULL)
862                 return FOREIGN_ERR;
863
864         lock(ctx);
865         pthread_cleanup_push(unlock, ctx);
866         rc = _delete_map(ctx, ud);
867         pthread_cleanup_pop(1);
868
869         if (rc == FOREIGN_OK)
870                 condlog(3, "%s: %s: map %s deleted", __func__, THIS,
871                         udev_device_get_sysname(ud));
872         else if (rc != FOREIGN_IGNORED)
873                 condlog(1, "%s: %s: retcode %d deleting map %s", __func__,
874                         THIS, rc, udev_device_get_sysname(ud));
875
876         return rc;
877 }
878
879 void _check(struct context *ctx)
880 {
881         struct gen_multipath *gm;
882         int i;
883
884         vector_foreach_slot(ctx->mpvec, gm, i) {
885                 struct nvme_map *map = gen_mp_to_nvme(gm);
886
887                 _find_controllers(ctx, map);
888         }
889 }
890
891 void check(struct context *ctx)
892 {
893         condlog(4, "%s called for \"%s\"", __func__, THIS);
894         lock(ctx);
895         pthread_cleanup_push(unlock, ctx);
896         _check(ctx);
897         pthread_cleanup_pop(1);
898         return;
899 }
900
901 /*
902  * It's safe to pass our internal pointer, this is only used under the lock.
903  */
904 const struct _vector *get_multipaths(const struct context *ctx)
905 {
906         condlog(5, "%s called for \"%s\"", __func__, THIS);
907         return ctx->mpvec;
908 }
909
910 void release_multipaths(__attribute__((unused)) const struct context *ctx,
911                         __attribute__((unused)) const struct _vector *mpvec)
912 {
913         condlog(5, "%s called for \"%s\"", __func__, THIS);
914         /* NOP */
915 }
916
917 /*
918  * It's safe to pass our internal pointer, this is only used under the lock.
919  */
920 const struct _vector * get_paths(const struct context *ctx)
921 {
922         vector paths = NULL;
923         const struct gen_multipath *gm;
924         int i;
925
926         condlog(5, "%s called for \"%s\"", __func__, THIS);
927         vector_foreach_slot(ctx->mpvec, gm, i) {
928                 const struct nvme_map *nm = const_gen_mp_to_nvme(gm);
929                 paths = vector_convert(paths, &nm->pgvec,
930                                        struct nvme_pathgroup, nvme_pg_to_path);
931         }
932         return paths;
933 }
934
935 void release_paths(__attribute__((unused)) const struct context *ctx,
936                    const struct _vector *mpvec)
937 {
938         condlog(5, "%s called for \"%s\"", __func__, THIS);
939         vector_free_const(mpvec);
940 }
941
942 /* compile-time check whether all methods are present and correctly typed */
943 #define _METHOD_INIT(x) .x = x
944 static struct foreign __methods __attribute__((unused)) = {
945         _METHOD_INIT(init),
946         _METHOD_INIT(cleanup),
947         _METHOD_INIT(change),
948         _METHOD_INIT(delete),
949         _METHOD_INIT(delete_all),
950         _METHOD_INIT(check),
951         _METHOD_INIT(lock),
952         _METHOD_INIT(unlock),
953         _METHOD_INIT(get_multipaths),
954         _METHOD_INIT(release_multipaths),
955         _METHOD_INIT(get_paths),
956         _METHOD_INIT(release_paths),
957 };