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