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