[multipath] consider the presence of conflicting empty maps
[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 static void
25 dm_restore_log (void)
26 {
27         dm_log_init(NULL);
28 }
29
30 static 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_status(char * name, char * outstatus)
223 {
224         int r = 1;
225         struct dm_task *dmt;
226         void *next = NULL;
227         uint64_t start, length;
228         char *target_type;
229         char *status;
230
231         if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
232                 return 1;
233
234         if (!dm_task_set_name(dmt, name))
235                 goto out;
236
237         dm_task_no_open_count(dmt);
238
239         if (!dm_task_run(dmt))
240                 goto out;
241
242         /* Fetch 1st target */
243         next = dm_get_next_target(dmt, next, &start, &length,
244                                   &target_type, &status);
245
246         if (snprintf(outstatus, PARAMS_SIZE, "%s", status) <= PARAMS_SIZE)
247                 r = 0;
248 out:
249         if (r)
250                 condlog(0, "%s: error getting map status string", name);
251
252         dm_task_destroy(dmt);
253         return r;
254 }
255
256 extern int
257 dm_type(char * name, char * type)
258 {
259         int r = 0;
260         struct dm_task *dmt;
261         void *next = NULL;
262         uint64_t start, length;
263         char *target_type = NULL;
264         char *params;
265
266         if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
267                 return 0;
268
269         if (!dm_task_set_name(dmt, name))
270                 goto out;
271
272         dm_task_no_open_count(dmt);
273
274         if (!dm_task_run(dmt))
275                 goto out;
276
277         /* Fetch 1st target */
278         next = dm_get_next_target(dmt, next, &start, &length,
279                                   &target_type, &params);
280
281         if (!target_type)
282                 r = -1;
283         else if (!strcmp(target_type, type))
284                 r = 1;
285
286 out:
287         dm_task_destroy(dmt);
288         return r;
289 }
290
291 static int
292 dm_dev_t (char * mapname, char * dev_t, int len)
293 {
294         int r = 1;
295         struct dm_task *dmt;
296         struct dm_info info;
297
298         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
299                 return 0;
300
301         if (!dm_task_set_name(dmt, mapname))
302                 goto out;
303
304         if (!dm_task_run(dmt))
305                 goto out;
306
307         if (!dm_task_get_info(dmt, &info))
308                 goto out;
309
310         r = info.open_count;
311         if (snprintf(dev_t, len, "%i:%i", info.major, info.minor) > len)
312                     goto out;
313
314         r = 0;
315 out:
316         dm_task_destroy(dmt);
317         return r;
318 }
319         
320 int
321 dm_get_opencount (char * mapname)
322 {
323         int r = -1;
324         struct dm_task *dmt;
325         struct dm_info info;
326
327         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
328                 return 0;
329
330         if (!dm_task_set_name(dmt, mapname))
331                 goto out;
332
333         if (!dm_task_run(dmt))
334                 goto out;
335
336         if (!dm_task_get_info(dmt, &info))
337                 goto out;
338
339         r = info.open_count;
340 out:
341         dm_task_destroy(dmt);
342         return r;
343 }
344         
345 int
346 dm_get_minor (char * mapname)
347 {
348         int r = -1;
349         struct dm_task *dmt;
350         struct dm_info info;
351
352         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
353                 return 0;
354
355         if (!dm_task_set_name(dmt, mapname))
356                 goto out;
357
358         if (!dm_task_run(dmt))
359                 goto out;
360
361         if (!dm_task_get_info(dmt, &info))
362                 goto out;
363
364         r = info.minor;
365 out:
366         dm_task_destroy(dmt);
367         return r;
368 }
369         
370 extern int
371 dm_flush_map (char * mapname, char * type)
372 {
373         int r;
374
375         if (!dm_map_present(mapname))
376                 return 0;
377
378         if (type && dm_type(mapname, type) <= 0)
379                 return 1;
380
381         if (dm_remove_partmaps(mapname))
382                 return 1;
383
384         if (dm_get_opencount(mapname))
385                 return 1;
386
387         r = dm_simplecmd(DM_DEVICE_REMOVE, mapname);
388
389         if (r) {
390                 condlog(4, "multipath map %s removed", mapname);
391                 return 0;
392         }
393         return 1;
394 }
395
396 extern int
397 dm_flush_maps (char * type)
398 {
399         int r = 0;
400         struct dm_task *dmt;
401         struct dm_names *names;
402         unsigned next = 0;
403
404         if (!(dmt = dm_task_create (DM_DEVICE_LIST)))
405                 return 0;
406
407         dm_task_no_open_count(dmt);
408
409         if (!dm_task_run (dmt))
410                 goto out;
411
412         if (!(names = dm_task_get_names (dmt)))
413                 goto out;
414
415         if (!names->dev)
416                 goto out;
417
418         do {
419                 r += dm_flush_map(names->name, type);
420                 next = names->next;
421                 names = (void *) names + next;
422         } while (next);
423
424         out:
425         dm_task_destroy (dmt);
426         return r;
427 }
428
429 int
430 dm_fail_path(char * mapname, char * path)
431 {
432         int r = 1;
433         struct dm_task *dmt;
434         char str[32];
435
436         if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
437                 return 1;
438
439         if (!dm_task_set_name(dmt, mapname))
440                 goto out;
441
442         if (!dm_task_set_sector(dmt, 0))
443                 goto out;
444
445         if (snprintf(str, 32, "fail_path %s\n", path) > 32)
446                 goto out;
447
448         if (!dm_task_set_message(dmt, str))
449                 goto out;
450
451         dm_task_no_open_count(dmt);
452
453         if (!dm_task_run(dmt))
454                 goto out;
455
456         r = 0;
457 out:
458         dm_task_destroy(dmt);
459         return r;
460 }
461
462 int
463 dm_reinstate(char * mapname, char * path)
464 {
465         int r = 1;
466         struct dm_task *dmt;
467         char str[32];
468
469         if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
470                 return 1;
471
472         if (!dm_task_set_name(dmt, mapname))
473                 goto out;
474
475         if (!dm_task_set_sector(dmt, 0))
476                 goto out;
477
478         if (snprintf(str, 32, "reinstate_path %s\n", path) > 32)
479                 goto out;
480
481         if (!dm_task_set_message(dmt, str))
482                 goto out;
483
484         dm_task_no_open_count(dmt);
485
486         if (!dm_task_run(dmt))
487                 goto out;
488
489         r = 0;
490 out:
491         dm_task_destroy(dmt);
492         return r;
493 }
494
495 int
496 dm_queue_if_no_path(char *mapname, int enable)
497 {
498         int r = 1;
499         struct dm_task *dmt;
500         char *str;
501
502         if (enable)
503                 str = "queue_if_no_path\n";
504         else
505                 str = "fail_if_no_path\n";
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 (!dm_task_set_message(dmt, str))
517                 goto out;
518
519         dm_task_no_open_count(dmt);
520
521         if (!dm_task_run(dmt))
522                 goto out;
523
524         r = 0;
525 out:
526         dm_task_destroy(dmt);
527         return r;
528 }
529
530 static int
531 dm_groupmsg (char * msg, char * mapname, int index)
532 {
533         int r = 0;
534         struct dm_task *dmt;
535         char str[24];
536
537         if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
538                 return 0;
539
540         if (!dm_task_set_name(dmt, mapname))
541                 goto out;
542
543         if (!dm_task_set_sector(dmt, 0))
544                 goto out;
545
546         snprintf(str, 24, "%s_group %i\n", msg, index);
547
548         if (!dm_task_set_message(dmt, str))
549                 goto out;
550
551         dm_task_no_open_count(dmt);
552
553         if (!dm_task_run(dmt))
554                 goto out;
555
556         condlog(3, "message %s 0 %s", mapname, str);
557         r = 1;
558
559         out:
560         if (!r)
561                 condlog(3, "message %s 0 %s failed", mapname, str);
562
563         dm_task_destroy(dmt);
564
565         return r;
566 }
567
568 int
569 dm_switchgroup(char * mapname, int index)
570 {
571         return dm_groupmsg("switch", mapname,index);
572 }
573
574 int
575 dm_enablegroup(char * mapname, int index)
576 {
577         return dm_groupmsg("enable", mapname,index);
578 }
579
580 int
581 dm_disablegroup(char * mapname, int index)
582 {
583         return dm_groupmsg("disable", mapname,index);
584 }
585
586 int
587 dm_get_maps (vector mp, char * type)
588 {
589         struct multipath * mpp;
590         int r = 1;
591         int info;
592         struct dm_task *dmt;
593         struct dm_names *names;
594         unsigned next = 0;
595
596         if (!type || !mp)
597                 return 1;
598
599         if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
600                 return 1;
601
602         dm_task_no_open_count(dmt);
603
604         if (!dm_task_run(dmt))
605                 goto out;
606
607         if (!(names = dm_task_get_names(dmt)))
608                 goto out;
609
610         if (!names->dev) {
611                 r = 0; /* this is perfectly valid */
612                 goto out;
613         }
614
615         do {
616                 info = dm_type(names->name, type);
617
618                 if (!info)
619                         goto next;
620
621                 mpp = alloc_multipath();
622
623                 if (!mpp)
624                         goto out;
625
626                 mpp->alias = STRDUP(names->name);
627
628                 if (!mpp->alias)
629                         goto out1;
630
631                 if (info > 0) {
632                         if (dm_get_map(names->name, &mpp->size, mpp->params))
633                                 goto out1;
634
635                         if (dm_get_status(names->name, mpp->status))
636                                 goto out1;
637
638                         dm_get_uuid(names->name, mpp->wwid);
639                 }
640
641                 if (!vector_alloc_slot(mp))
642                         goto out1;
643
644                 vector_set_slot(mp, mpp);
645                 mpp = NULL;
646 next:
647                 next = names->next;
648                 names = (void *) names + next;
649         } while (next);
650
651         r = 0;
652         goto out;
653 out1:
654         free_multipath(mpp, KEEP_PATHS);
655 out:
656         dm_task_destroy (dmt);
657         return r;
658 }
659
660 int
661 dm_geteventnr (char *name)
662 {
663         struct dm_task *dmt;
664         struct dm_info info;
665
666         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
667                 return 0;
668
669         if (!dm_task_set_name(dmt, name))
670                 goto out;
671
672         dm_task_no_open_count(dmt);
673
674         if (!dm_task_run(dmt))
675                 goto out;
676
677         if (!dm_task_get_info(dmt, &info)) {
678                 info.event_nr = 0;
679                 goto out;
680         }
681
682         if (!info.exists) {
683                 info.event_nr = 0;
684                 goto out;
685         }
686
687 out:
688         dm_task_destroy(dmt);
689
690         return info.event_nr;
691 }
692
693 char *
694 dm_mapname(int major, int minor)
695 {
696         char * response;
697         struct dm_task *dmt;
698         int r;
699         int loop = MAX_WAIT * LOOPS_PER_SEC;
700
701         if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
702                 return NULL;
703
704         if (!dm_task_set_major(dmt, major) ||
705             !dm_task_set_minor(dmt, minor))
706                 goto bad;
707
708         dm_task_no_open_count(dmt);
709
710         /*
711          * device map might not be ready when we get here from
712          * daemon uev_trigger -> uev_add_map
713          */
714         while (--loop) {
715                 dm_shut_log();
716                 r = dm_task_run(dmt);
717                 dm_restore_log();
718
719                 if (r)
720                         break;
721
722                 usleep(1000 * 1000 / LOOPS_PER_SEC);
723         }
724
725         if (!r) {
726                 condlog(0, "%i:%i: timeout fetching map name", major, minor);
727                 goto bad;
728         }
729
730         response = STRDUP((char *)dm_task_get_name(dmt));
731         dm_task_destroy(dmt);
732         return response;
733 bad:
734         dm_task_destroy(dmt);
735         condlog(0, "%i:%i: error fetching map name", major, minor);
736         return NULL;
737 }
738
739 int
740 dm_remove_partmaps (char * mapname)
741 {
742         struct dm_task *dmt;
743         struct dm_names *names;
744         unsigned next = 0;
745         char params[PARAMS_SIZE];
746         unsigned long long size;
747         char dev_t[32];
748         int r = 1;
749
750         if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
751                 return 1;
752
753         dm_task_no_open_count(dmt);
754
755         if (!dm_task_run(dmt))
756                 goto out;
757
758         if (!(names = dm_task_get_names(dmt)))
759                 goto out;
760
761         if (!names->dev) {
762                 r = 0; /* this is perfectly valid */
763                 goto out;
764         }
765
766         if (dm_dev_t(mapname, &dev_t[0], 32))
767                 goto out;
768
769         do {
770                 if (
771                     /*
772                      * if devmap target is "linear"
773                      */
774                     dm_type(names->name, "linear") &&
775
776                     /*
777                      * and the multipath mapname and the part mapname start
778                      * the same
779                      */
780                     !strncmp(names->name, mapname, strlen(mapname)) &&
781
782                     /*
783                      * and the opencount is 0 for us to allow removal
784                      */
785                     !dm_get_opencount(names->name) &&
786
787                     /*
788                      * and we can fetch the map table from the kernel
789                      */
790                     !dm_get_map(names->name, &size, &params[0]) &&
791
792                     /*
793                      * and the table maps over the multipath map
794                      */
795                     strstr(params, dev_t)
796                    ) {
797                                 /*
798                                  * then it's a kpartx generated partition.
799                                  * remove it.
800                                  */
801                                 condlog(4, "partition map %s removed",
802                                         names->name);
803                                 dm_simplecmd(DM_DEVICE_REMOVE, names->name);
804                    }
805
806                 next = names->next;
807                 names = (void *) names + next;
808         } while (next);
809
810         r = 0;
811 out:
812         dm_task_destroy (dmt);
813         return r;
814 }
815
816 #if 0
817 int
818 dm_rename (char * old, char * new)
819 {
820         int r = 1;
821         struct dm_task *dmt;
822
823         if (!(dmt = dm_task_create(DM_DEVICE_RENAME)))
824                 return 0;
825
826         if (!dm_task_set_name(dmt, old))
827                 goto out;
828
829         if (!dm_task_set_newname(dmt, new))
830                 goto out;
831         
832         dm_task_no_open_count(dmt);
833
834         if (!dm_task_run(dmt))
835                 goto out;
836
837         r = 0;
838 out:
839         dm_task_destroy(dmt);
840         return r;
841 }
842 #endif