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