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