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