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