[libmultipath] message when a map can't be flush because in use
[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 /*
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_fail_path(char * mapname, char * path)
439 {
440         int r = 1;
441         struct dm_task *dmt;
442         char str[32];
443
444         if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
445                 return 1;
446
447         if (!dm_task_set_name(dmt, mapname))
448                 goto out;
449
450         if (!dm_task_set_sector(dmt, 0))
451                 goto out;
452
453         if (snprintf(str, 32, "fail_path %s\n", path) > 32)
454                 goto out;
455
456         if (!dm_task_set_message(dmt, str))
457                 goto out;
458
459         dm_task_no_open_count(dmt);
460
461         if (!dm_task_run(dmt))
462                 goto out;
463
464         r = 0;
465 out:
466         dm_task_destroy(dmt);
467         return r;
468 }
469
470 int
471 dm_reinstate(char * mapname, char * path)
472 {
473         int r = 1;
474         struct dm_task *dmt;
475         char str[32];
476
477         if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
478                 return 1;
479
480         if (!dm_task_set_name(dmt, mapname))
481                 goto out;
482
483         if (!dm_task_set_sector(dmt, 0))
484                 goto out;
485
486         if (snprintf(str, 32, "reinstate_path %s\n", path) > 32)
487                 goto out;
488
489         if (!dm_task_set_message(dmt, str))
490                 goto out;
491
492         dm_task_no_open_count(dmt);
493
494         if (!dm_task_run(dmt))
495                 goto out;
496
497         r = 0;
498 out:
499         dm_task_destroy(dmt);
500         return r;
501 }
502
503 int
504 dm_queue_if_no_path(char *mapname, int enable)
505 {
506         int r = 1;
507         struct dm_task *dmt;
508         char *str;
509
510         if (enable)
511                 str = "queue_if_no_path\n";
512         else
513                 str = "fail_if_no_path\n";
514
515         if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
516                 return 1;
517
518         if (!dm_task_set_name(dmt, mapname))
519                 goto out;
520
521         if (!dm_task_set_sector(dmt, 0))
522                 goto out;
523
524         if (!dm_task_set_message(dmt, str))
525                 goto out;
526
527         dm_task_no_open_count(dmt);
528
529         if (!dm_task_run(dmt))
530                 goto out;
531
532         r = 0;
533 out:
534         dm_task_destroy(dmt);
535         return r;
536 }
537
538 static int
539 dm_groupmsg (char * msg, char * mapname, int index)
540 {
541         int r = 0;
542         struct dm_task *dmt;
543         char str[24];
544
545         if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
546                 return 0;
547
548         if (!dm_task_set_name(dmt, mapname))
549                 goto out;
550
551         if (!dm_task_set_sector(dmt, 0))
552                 goto out;
553
554         snprintf(str, 24, "%s_group %i\n", msg, index);
555
556         if (!dm_task_set_message(dmt, str))
557                 goto out;
558
559         dm_task_no_open_count(dmt);
560
561         if (!dm_task_run(dmt))
562                 goto out;
563
564         condlog(3, "message %s 0 %s", mapname, str);
565         r = 1;
566
567         out:
568         if (!r)
569                 condlog(3, "message %s 0 %s failed", mapname, str);
570
571         dm_task_destroy(dmt);
572
573         return r;
574 }
575
576 int
577 dm_switchgroup(char * mapname, int index)
578 {
579         return dm_groupmsg("switch", mapname,index);
580 }
581
582 int
583 dm_enablegroup(char * mapname, int index)
584 {
585         return dm_groupmsg("enable", mapname,index);
586 }
587
588 int
589 dm_disablegroup(char * mapname, int index)
590 {
591         return dm_groupmsg("disable", mapname,index);
592 }
593
594 int
595 dm_get_maps (vector mp, char * type)
596 {
597         struct multipath * mpp;
598         int r = 1;
599         int info;
600         struct dm_task *dmt;
601         struct dm_names *names;
602         unsigned next = 0;
603
604         if (!type || !mp)
605                 return 1;
606
607         if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
608                 return 1;
609
610         dm_task_no_open_count(dmt);
611
612         if (!dm_task_run(dmt))
613                 goto out;
614
615         if (!(names = dm_task_get_names(dmt)))
616                 goto out;
617
618         if (!names->dev) {
619                 r = 0; /* this is perfectly valid */
620                 goto out;
621         }
622
623         do {
624                 info = dm_type(names->name, type);
625
626                 if (!info)
627                         goto next;
628
629                 mpp = alloc_multipath();
630
631                 if (!mpp)
632                         goto out;
633
634                 mpp->alias = STRDUP(names->name);
635
636                 if (!mpp->alias)
637                         goto out1;
638
639                 if (info > 0) {
640                         if (dm_get_map(names->name, &mpp->size, mpp->params))
641                                 goto out1;
642
643                         if (dm_get_status(names->name, mpp->status))
644                                 goto out1;
645
646                         dm_get_uuid(names->name, mpp->wwid);
647                 }
648
649                 if (!vector_alloc_slot(mp))
650                         goto out1;
651
652                 vector_set_slot(mp, mpp);
653                 mpp = NULL;
654 next:
655                 next = names->next;
656                 names = (void *) names + next;
657         } while (next);
658
659         r = 0;
660         goto out;
661 out1:
662         free_multipath(mpp, KEEP_PATHS);
663 out:
664         dm_task_destroy (dmt);
665         return r;
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;
705         struct dm_task *dmt;
706         int r;
707         int loop = MAX_WAIT * LOOPS_PER_SEC;
708
709         if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
710                 return NULL;
711
712         if (!dm_task_set_major(dmt, major) ||
713             !dm_task_set_minor(dmt, minor))
714                 goto bad;
715
716         dm_task_no_open_count(dmt);
717
718         /*
719          * device map might not be ready when we get here from
720          * daemon uev_trigger -> uev_add_map
721          */
722         while (--loop) {
723                 dm_shut_log();
724                 r = dm_task_run(dmt);
725                 dm_restore_log();
726
727                 if (r)
728                         break;
729
730                 usleep(1000 * 1000 / LOOPS_PER_SEC);
731         }
732
733         if (!r) {
734                 condlog(0, "%i:%i: timeout fetching map name", major, minor);
735                 goto bad;
736         }
737
738         response = STRDUP((char *)dm_task_get_name(dmt));
739         dm_task_destroy(dmt);
740         return response;
741 bad:
742         dm_task_destroy(dmt);
743         condlog(0, "%i:%i: error fetching map name", major, minor);
744         return NULL;
745 }
746
747 int
748 dm_remove_partmaps (char * mapname)
749 {
750         struct dm_task *dmt;
751         struct dm_names *names;
752         unsigned next = 0;
753         char params[PARAMS_SIZE];
754         unsigned long long size;
755         char dev_t[32];
756         int r = 1;
757
758         if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
759                 return 1;
760
761         dm_task_no_open_count(dmt);
762
763         if (!dm_task_run(dmt))
764                 goto out;
765
766         if (!(names = dm_task_get_names(dmt)))
767                 goto out;
768
769         if (!names->dev) {
770                 r = 0; /* this is perfectly valid */
771                 goto out;
772         }
773
774         if (dm_dev_t(mapname, &dev_t[0], 32))
775                 goto out;
776
777         do {
778                 if (
779                     /*
780                      * if devmap target is "linear"
781                      */
782                     dm_type(names->name, "linear") &&
783
784                     /*
785                      * and the multipath mapname and the part mapname start
786                      * the same
787                      */
788                     !strncmp(names->name, mapname, strlen(mapname)) &&
789
790                     /*
791                      * and the opencount is 0 for us to allow removal
792                      */
793                     !dm_get_opencount(names->name) &&
794
795                     /*
796                      * and we can fetch the map table from the kernel
797                      */
798                     !dm_get_map(names->name, &size, &params[0]) &&
799
800                     /*
801                      * and the table maps over the multipath map
802                      */
803                     strstr(params, dev_t)
804                    ) {
805                                 /*
806                                  * then it's a kpartx generated partition.
807                                  * remove it.
808                                  */
809                                 condlog(4, "partition map %s removed",
810                                         names->name);
811                                 dm_simplecmd(DM_DEVICE_REMOVE, names->name);
812                    }
813
814                 next = names->next;
815                 names = (void *) names + next;
816         } while (next);
817
818         r = 0;
819 out:
820         dm_task_destroy (dmt);
821         return r;
822 }
823
824 #if 0
825 int
826 dm_rename (char * old, char * new)
827 {
828         int r = 1;
829         struct dm_task *dmt;
830
831         if (!(dmt = dm_task_create(DM_DEVICE_RENAME)))
832                 return 0;
833
834         if (!dm_task_set_name(dmt, old))
835                 goto out;
836
837         if (!dm_task_set_newname(dmt, new))
838                 goto out;
839         
840         dm_task_no_open_count(dmt);
841
842         if (!dm_task_run(dmt))
843                 goto out;
844
845         r = 0;
846 out:
847         dm_task_destroy(dmt);
848         return r;
849 }
850 #endif