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