[multipathd] handle map dmstate reporting through "show maps" CLI cmd
[platform/upstream/multipath-tools.git] / libmultipath / devmapper.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <libdevmapper.h>
5 #include <ctype.h>
6 #include <linux/kdev_t.h>
7 #include <unistd.h>
8
9 #include "vector.h"
10 #include "structs.h"
11 #include "debug.h"
12 #include "memory.h"
13 #include "devmapper.h"
14
15 #define MAX_WAIT 5
16 #define LOOPS_PER_SEC 5
17
18 static void
19 dm_dummy_log (int level, const char *file, int line, const char *f, ...)
20 {
21         return;
22 }
23
24 void
25 dm_restore_log (void)
26 {
27         dm_log_init(NULL);
28 }
29
30 void
31 dm_shut_log (void)
32 {
33         dm_log_init(&dm_dummy_log);
34 }
35
36 extern int
37 dm_prereq (char * str, int x, int y, int z)
38 {
39         int r = 2;
40         struct dm_task *dmt;
41         struct dm_versions *target;
42         struct dm_versions *last_target;
43
44         if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
45                 return 3;
46
47         dm_task_no_open_count(dmt);
48
49         if (!dm_task_run(dmt)) {
50                 condlog(0, "Can not communicate with kernel DM");
51                 goto out;
52         }
53
54         target = dm_task_get_versions(dmt);
55
56         do {
57                 last_target = target;
58
59                 if (!strncmp(str, target->name, strlen(str))) {
60                         r--;
61                         
62                         if (target->version[0] >= x &&
63                             target->version[1] >= y &&
64                             target->version[2] >= z)
65                                 r--;
66
67                         break;
68                 }
69
70                 target = (void *) target + target->next;
71         } while (last_target != target);
72
73         if (r == 2)
74                 condlog(0, "DM multipath kernel driver not loaded");
75         else if (r == 1)
76                 condlog(0, "DM multipath kernel driver version too old");
77
78 out:
79         dm_task_destroy(dmt);
80         return r;
81 }
82
83 extern int
84 dm_simplecmd (int task, const char *name) {
85         int r = 0;
86         struct dm_task *dmt;
87
88         if (!(dmt = dm_task_create (task)))
89                 return 0;
90
91         if (!dm_task_set_name (dmt, name))
92                 goto out;
93
94         dm_task_no_open_count(dmt);
95
96         r = dm_task_run (dmt);
97
98         out:
99         dm_task_destroy (dmt);
100         return r;
101 }
102
103 extern int
104 dm_addmap (int task, const char *name, const char *target,
105            const char *params, unsigned long long size, const char *uuid) {
106         int r = 0;
107         struct dm_task *dmt;
108
109         if (!(dmt = dm_task_create (task)))
110                 return 0;
111
112         if (!dm_task_set_name (dmt, name))
113                 goto addout;
114
115         if (!dm_task_add_target (dmt, 0, size, target, params))
116                 goto addout;
117
118         if (uuid && !dm_task_set_uuid(dmt, uuid))
119                 goto addout;
120
121         dm_task_no_open_count(dmt);
122
123         r = dm_task_run (dmt);
124
125         addout:
126         dm_task_destroy (dmt);
127         return r;
128 }
129
130 extern int
131 dm_map_present (char * str)
132 {
133         int r = 0;
134         struct dm_task *dmt;
135         struct dm_info info;
136
137         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
138                 return 0;
139
140         if (!dm_task_set_name(dmt, str))
141                 goto out;
142
143         dm_task_no_open_count(dmt);
144
145         if (!dm_task_run(dmt))
146                 goto out;
147
148         if (!dm_task_get_info(dmt, &info))
149                 goto out;
150
151         if (info.exists)
152                 r = 1;
153 out:
154         dm_task_destroy(dmt);
155         return r;
156 }
157
158 extern int
159 dm_get_map(char * name, unsigned long long * size, char * outparams)
160 {
161         int r = 1;
162         struct dm_task *dmt;
163         void *next = NULL;
164         uint64_t start, length;
165         char *target_type = NULL;
166         char *params = NULL;
167
168         if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
169                 return 1;
170
171         if (!dm_task_set_name(dmt, name))
172                 goto out;
173
174         dm_task_no_open_count(dmt);
175
176         if (!dm_task_run(dmt))
177                 goto out;
178
179         /* Fetch 1st target */
180         next = dm_get_next_target(dmt, next, &start, &length,
181                                   &target_type, &params);
182
183         if (size)
184                 *size = length;
185
186         if (snprintf(outparams, PARAMS_SIZE, "%s", params) <= PARAMS_SIZE)
187                 r = 0;
188 out:
189         dm_task_destroy(dmt);
190         return r;
191 }
192
193 extern int
194 dm_get_uuid(char *name, char *uuid)
195 {
196         struct dm_task *dmt;
197         const char *uuidtmp;
198
199         dmt = dm_task_create(DM_DEVICE_INFO);
200         if (!dmt)
201                 return 1;
202
203         if (!dm_task_set_name (dmt, name))
204                 goto uuidout;
205
206         if (!dm_task_run(dmt))
207                 goto uuidout;
208
209         uuidtmp = dm_task_get_uuid(dmt);
210         if (uuidtmp)
211                 strcpy(uuid, uuidtmp);
212         else
213                 uuid[0] = '\0';
214
215 uuidout:
216         dm_task_destroy(dmt);
217
218         return 0;
219 }
220
221 extern int
222 dm_get_state(char *name, int *state)
223 {
224         struct dm_task *dmt;
225         struct dm_info info;
226
227         dmt = dm_task_create(DM_DEVICE_INFO);
228         if (!dmt)
229                 return 1;
230
231         if (!dm_task_set_name (dmt, name))
232                 goto out;
233
234         if (!dm_task_run(dmt))
235                 goto out;
236
237         if (!dm_task_get_info(dmt, &info))
238                 goto out;
239
240         *state = info.suspended;
241         if (info.suspended)
242                 *state = MAPSTATE_SUSPENDED;
243         else
244                 *state = MAPSTATE_ACTIVE;
245
246 out:
247         dm_task_destroy(dmt);
248         return 0;
249 }
250
251 extern int
252 dm_get_status(char * name, char * outstatus)
253 {
254         int r = 1;
255         struct dm_task *dmt;
256         void *next = NULL;
257         uint64_t start, length;
258         char *target_type;
259         char *status;
260
261         if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
262                 return 1;
263
264         if (!dm_task_set_name(dmt, name))
265                 goto out;
266
267         dm_task_no_open_count(dmt);
268
269         if (!dm_task_run(dmt))
270                 goto out;
271
272         /* Fetch 1st target */
273         next = dm_get_next_target(dmt, next, &start, &length,
274                                   &target_type, &status);
275
276         if (snprintf(outstatus, PARAMS_SIZE, "%s", status) <= PARAMS_SIZE)
277                 r = 0;
278 out:
279         if (r)
280                 condlog(0, "%s: error getting map status string", name);
281
282         dm_task_destroy(dmt);
283         return r;
284 }
285
286 /*
287  * returns:
288  *    1 : match
289  *    0 : no match
290  *   -1 : empty map
291  */
292 extern int
293 dm_type(char * name, char * type)
294 {
295         int r = 0;
296         struct dm_task *dmt;
297         void *next = NULL;
298         uint64_t start, length;
299         char *target_type = NULL;
300         char *params;
301
302         if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
303                 return 0;
304
305         if (!dm_task_set_name(dmt, name))
306                 goto out;
307
308         dm_task_no_open_count(dmt);
309
310         if (!dm_task_run(dmt))
311                 goto out;
312
313         /* Fetch 1st target */
314         next = dm_get_next_target(dmt, next, &start, &length,
315                                   &target_type, &params);
316
317         if (!target_type)
318                 r = -1;
319         else if (!strcmp(target_type, type))
320                 r = 1;
321
322 out:
323         dm_task_destroy(dmt);
324         return r;
325 }
326
327 static int
328 dm_dev_t (char * mapname, char * dev_t, int len)
329 {
330         int r = 1;
331         struct dm_task *dmt;
332         struct dm_info info;
333
334         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
335                 return 0;
336
337         if (!dm_task_set_name(dmt, mapname))
338                 goto out;
339
340         if (!dm_task_run(dmt))
341                 goto out;
342
343         if (!dm_task_get_info(dmt, &info))
344                 goto out;
345
346         r = info.open_count;
347         if (snprintf(dev_t, len, "%i:%i", info.major, info.minor) > len)
348                     goto out;
349
350         r = 0;
351 out:
352         dm_task_destroy(dmt);
353         return r;
354 }
355         
356 int
357 dm_get_opencount (char * mapname)
358 {
359         int r = -1;
360         struct dm_task *dmt;
361         struct dm_info info;
362
363         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
364                 return 0;
365
366         if (!dm_task_set_name(dmt, mapname))
367                 goto out;
368
369         if (!dm_task_run(dmt))
370                 goto out;
371
372         if (!dm_task_get_info(dmt, &info))
373                 goto out;
374
375         r = info.open_count;
376 out:
377         dm_task_destroy(dmt);
378         return r;
379 }
380         
381 int
382 dm_get_minor (char * mapname)
383 {
384         int r = -1;
385         struct dm_task *dmt;
386         struct dm_info info;
387
388         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
389                 return 0;
390
391         if (!dm_task_set_name(dmt, mapname))
392                 goto out;
393
394         if (!dm_task_run(dmt))
395                 goto out;
396
397         if (!dm_task_get_info(dmt, &info))
398                 goto out;
399
400         r = info.minor;
401 out:
402         dm_task_destroy(dmt);
403         return r;
404 }
405         
406 extern int
407 dm_flush_map (char * mapname, char * type)
408 {
409         int r;
410
411         if (!dm_map_present(mapname))
412                 return 0;
413
414         if (!dm_type(mapname, type))
415                 return 1;
416
417         if (dm_remove_partmaps(mapname))
418                 return 1;
419
420         if (dm_get_opencount(mapname)) {
421                 condlog(2, "%s: map in use", mapname);
422                 return 1;
423         }       
424
425         r = dm_simplecmd(DM_DEVICE_REMOVE, mapname);
426
427         if (r) {
428                 condlog(4, "multipath map %s removed", mapname);
429                 return 0;
430         }
431         return 1;
432 }
433
434 extern int
435 dm_flush_maps (char * type)
436 {
437         int r = 0;
438         struct dm_task *dmt;
439         struct dm_names *names;
440         unsigned next = 0;
441
442         if (!(dmt = dm_task_create (DM_DEVICE_LIST)))
443                 return 0;
444
445         dm_task_no_open_count(dmt);
446
447         if (!dm_task_run (dmt))
448                 goto out;
449
450         if (!(names = dm_task_get_names (dmt)))
451                 goto out;
452
453         if (!names->dev)
454                 goto out;
455
456         do {
457                 r += dm_flush_map(names->name, type);
458                 next = names->next;
459                 names = (void *) names + next;
460         } while (next);
461
462         out:
463         dm_task_destroy (dmt);
464         return r;
465 }
466
467 int
468 dm_fail_path(char * mapname, char * path)
469 {
470         int r = 1;
471         struct dm_task *dmt;
472         char str[32];
473
474         if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
475                 return 1;
476
477         if (!dm_task_set_name(dmt, mapname))
478                 goto out;
479
480         if (!dm_task_set_sector(dmt, 0))
481                 goto out;
482
483         if (snprintf(str, 32, "fail_path %s\n", path) > 32)
484                 goto out;
485
486         if (!dm_task_set_message(dmt, str))
487                 goto out;
488
489         dm_task_no_open_count(dmt);
490
491         if (!dm_task_run(dmt))
492                 goto out;
493
494         r = 0;
495 out:
496         dm_task_destroy(dmt);
497         return r;
498 }
499
500 int
501 dm_reinstate(char * mapname, char * path)
502 {
503         int r = 1;
504         struct dm_task *dmt;
505         char str[32];
506
507         if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
508                 return 1;
509
510         if (!dm_task_set_name(dmt, mapname))
511                 goto out;
512
513         if (!dm_task_set_sector(dmt, 0))
514                 goto out;
515
516         if (snprintf(str, 32, "reinstate_path %s\n", path) > 32)
517                 goto out;
518
519         if (!dm_task_set_message(dmt, str))
520                 goto out;
521
522         dm_task_no_open_count(dmt);
523
524         if (!dm_task_run(dmt))
525                 goto out;
526
527         r = 0;
528 out:
529         dm_task_destroy(dmt);
530         return r;
531 }
532
533 int
534 dm_queue_if_no_path(char *mapname, int enable)
535 {
536         int r = 1;
537         struct dm_task *dmt;
538         char *str;
539
540         if (enable)
541                 str = "queue_if_no_path\n";
542         else
543                 str = "fail_if_no_path\n";
544
545         if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
546                 return 1;
547
548         if (!dm_task_set_name(dmt, mapname))
549                 goto out;
550
551         if (!dm_task_set_sector(dmt, 0))
552                 goto out;
553
554         if (!dm_task_set_message(dmt, str))
555                 goto out;
556
557         dm_task_no_open_count(dmt);
558
559         if (!dm_task_run(dmt))
560                 goto out;
561
562         r = 0;
563 out:
564         dm_task_destroy(dmt);
565         return r;
566 }
567
568 static int
569 dm_groupmsg (char * msg, char * mapname, int index)
570 {
571         int r = 0;
572         struct dm_task *dmt;
573         char str[24];
574
575         if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
576                 return 0;
577
578         if (!dm_task_set_name(dmt, mapname))
579                 goto out;
580
581         if (!dm_task_set_sector(dmt, 0))
582                 goto out;
583
584         snprintf(str, 24, "%s_group %i\n", msg, index);
585
586         if (!dm_task_set_message(dmt, str))
587                 goto out;
588
589         dm_task_no_open_count(dmt);
590
591         if (!dm_task_run(dmt))
592                 goto out;
593
594         condlog(3, "message %s 0 %s", mapname, str);
595         r = 1;
596
597         out:
598         if (!r)
599                 condlog(3, "message %s 0 %s failed", mapname, str);
600
601         dm_task_destroy(dmt);
602
603         return r;
604 }
605
606 int
607 dm_switchgroup(char * mapname, int index)
608 {
609         return dm_groupmsg("switch", mapname,index);
610 }
611
612 int
613 dm_enablegroup(char * mapname, int index)
614 {
615         return dm_groupmsg("enable", mapname,index);
616 }
617
618 int
619 dm_disablegroup(char * mapname, int index)
620 {
621         return dm_groupmsg("disable", mapname,index);
622 }
623
624 int
625 dm_get_maps (vector mp, char * type)
626 {
627         struct multipath * mpp;
628         int r = 1;
629         int info;
630         struct dm_task *dmt;
631         struct dm_names *names;
632         unsigned next = 0;
633
634         if (!type || !mp)
635                 return 1;
636
637         if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
638                 return 1;
639
640         dm_task_no_open_count(dmt);
641
642         if (!dm_task_run(dmt))
643                 goto out;
644
645         if (!(names = dm_task_get_names(dmt)))
646                 goto out;
647
648         if (!names->dev) {
649                 r = 0; /* this is perfectly valid */
650                 goto out;
651         }
652
653         do {
654                 info = dm_type(names->name, type);
655
656                 if (!info)
657                         goto next;
658
659                 mpp = alloc_multipath();
660
661                 if (!mpp)
662                         goto out;
663
664                 mpp->alias = STRDUP(names->name);
665
666                 if (!mpp->alias)
667                         goto out1;
668
669                 if (info > 0) {
670                         if (dm_get_map(names->name, &mpp->size, mpp->params))
671                                 goto out1;
672
673                         if (dm_get_status(names->name, mpp->status))
674                                 goto out1;
675
676                         dm_get_uuid(names->name, mpp->wwid);
677                         dm_get_state(names->name, &mpp->dmstate);
678                 }
679
680                 if (!vector_alloc_slot(mp))
681                         goto out1;
682
683                 vector_set_slot(mp, mpp);
684                 mpp = NULL;
685 next:
686                 next = names->next;
687                 names = (void *) names + next;
688         } while (next);
689
690         r = 0;
691         goto out;
692 out1:
693         free_multipath(mpp, KEEP_PATHS);
694 out:
695         dm_task_destroy (dmt);
696         return r;
697 }
698
699 int
700 dm_geteventnr (char *name)
701 {
702         struct dm_task *dmt;
703         struct dm_info info;
704
705         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
706                 return 0;
707
708         if (!dm_task_set_name(dmt, name))
709                 goto out;
710
711         dm_task_no_open_count(dmt);
712
713         if (!dm_task_run(dmt))
714                 goto out;
715
716         if (!dm_task_get_info(dmt, &info)) {
717                 info.event_nr = 0;
718                 goto out;
719         }
720
721         if (!info.exists) {
722                 info.event_nr = 0;
723                 goto out;
724         }
725
726 out:
727         dm_task_destroy(dmt);
728
729         return info.event_nr;
730 }
731
732 char *
733 dm_mapname(int major, int minor)
734 {
735         char * response;
736         struct dm_task *dmt;
737         int r;
738         int loop = MAX_WAIT * LOOPS_PER_SEC;
739
740         if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
741                 return NULL;
742
743         if (!dm_task_set_major(dmt, major) ||
744             !dm_task_set_minor(dmt, minor))
745                 goto bad;
746
747         dm_task_no_open_count(dmt);
748
749         /*
750          * device map might not be ready when we get here from
751          * daemon uev_trigger -> uev_add_map
752          */
753         while (--loop) {
754                 dm_shut_log();
755                 r = dm_task_run(dmt);
756                 dm_restore_log();
757
758                 if (r)
759                         break;
760
761                 usleep(1000 * 1000 / LOOPS_PER_SEC);
762         }
763
764         if (!r) {
765                 condlog(0, "%i:%i: timeout fetching map name", major, minor);
766                 goto bad;
767         }
768
769         response = STRDUP((char *)dm_task_get_name(dmt));
770         dm_task_destroy(dmt);
771         return response;
772 bad:
773         dm_task_destroy(dmt);
774         condlog(0, "%i:%i: error fetching map name", major, minor);
775         return NULL;
776 }
777
778 int
779 dm_remove_partmaps (char * mapname)
780 {
781         struct dm_task *dmt;
782         struct dm_names *names;
783         unsigned next = 0;
784         char params[PARAMS_SIZE];
785         unsigned long long size;
786         char dev_t[32];
787         int r = 1;
788
789         if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
790                 return 1;
791
792         dm_task_no_open_count(dmt);
793
794         if (!dm_task_run(dmt))
795                 goto out;
796
797         if (!(names = dm_task_get_names(dmt)))
798                 goto out;
799
800         if (!names->dev) {
801                 r = 0; /* this is perfectly valid */
802                 goto out;
803         }
804
805         if (dm_dev_t(mapname, &dev_t[0], 32))
806                 goto out;
807
808         do {
809                 if (
810                     /*
811                      * if devmap target is "linear"
812                      */
813                     dm_type(names->name, "linear") &&
814
815                     /*
816                      * and the multipath mapname and the part mapname start
817                      * the same
818                      */
819                     !strncmp(names->name, mapname, strlen(mapname)) &&
820
821                     /*
822                      * and the opencount is 0 for us to allow removal
823                      */
824                     !dm_get_opencount(names->name) &&
825
826                     /*
827                      * and we can fetch the map table from the kernel
828                      */
829                     !dm_get_map(names->name, &size, &params[0]) &&
830
831                     /*
832                      * and the table maps over the multipath map
833                      */
834                     strstr(params, dev_t)
835                    ) {
836                                 /*
837                                  * then it's a kpartx generated partition.
838                                  * remove it.
839                                  */
840                                 condlog(4, "partition map %s removed",
841                                         names->name);
842                                 dm_simplecmd(DM_DEVICE_REMOVE, names->name);
843                    }
844
845                 next = names->next;
846                 names = (void *) names + next;
847         } while (next);
848
849         r = 0;
850 out:
851         dm_task_destroy (dmt);
852         return r;
853 }
854
855 #if 0
856 int
857 dm_rename (char * old, char * new)
858 {
859         int r = 1;
860         struct dm_task *dmt;
861
862         if (!(dmt = dm_task_create(DM_DEVICE_RENAME)))
863                 return 0;
864
865         if (!dm_task_set_name(dmt, old))
866                 goto out;
867
868         if (!dm_task_set_newname(dmt, new))
869                 goto out;
870         
871         dm_task_no_open_count(dmt);
872
873         if (!dm_task_run(dmt))
874                 goto out;
875
876         r = 0;
877 out:
878         dm_task_destroy(dmt);
879         return r;
880 }
881 #endif