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