[multipathd] shut a libdevmapper error message when adding paths
[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) {
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         dm_task_no_open_count(dmt);
119
120         r = dm_task_run (dmt);
121
122         addout:
123         dm_task_destroy (dmt);
124         return r;
125 }
126
127 extern int
128 dm_map_present (char * str)
129 {
130         int r = 0;
131         struct dm_task *dmt;
132         struct dm_info info;
133
134         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
135                 return 0;
136
137         if (!dm_task_set_name(dmt, str))
138                 goto out;
139
140         dm_task_no_open_count(dmt);
141
142         if (!dm_task_run(dmt))
143                 goto out;
144
145         if (!dm_task_get_info(dmt, &info))
146                 goto out;
147
148         if (info.exists)
149                 r = 1;
150 out:
151         dm_task_destroy(dmt);
152         return r;
153 }
154
155 extern int
156 dm_get_map(char * name, unsigned long long * size, char * outparams)
157 {
158         int r = 1;
159         struct dm_task *dmt;
160         void *next = NULL;
161         uint64_t start, length;
162         char *target_type = NULL;
163         char *params = NULL;
164
165         if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
166                 return 1;
167
168         if (!dm_task_set_name(dmt, name))
169                 goto out;
170
171         dm_task_no_open_count(dmt);
172
173         if (!dm_task_run(dmt))
174                 goto out;
175
176         /* Fetch 1st target */
177         next = dm_get_next_target(dmt, next, &start, &length,
178                                   &target_type, &params);
179
180         if (size)
181                 *size = length;
182
183         if (snprintf(outparams, PARAMS_SIZE, "%s", params) <= PARAMS_SIZE)
184                 r = 0;
185 out:
186         dm_task_destroy(dmt);
187         return r;
188 }
189
190 extern int
191 dm_get_status(char * name, char * outstatus)
192 {
193         int r = 1;
194         struct dm_task *dmt;
195         void *next = NULL;
196         uint64_t start, length;
197         char *target_type;
198         char *status;
199
200         if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
201                 return 1;
202
203         if (!dm_task_set_name(dmt, name))
204                 goto out;
205
206         dm_task_no_open_count(dmt);
207
208         if (!dm_task_run(dmt))
209                 goto out;
210
211         /* Fetch 1st target */
212         next = dm_get_next_target(dmt, next, &start, &length,
213                                   &target_type, &status);
214
215         if (snprintf(outstatus, PARAMS_SIZE, "%s", status) <= PARAMS_SIZE)
216                 r = 0;
217 out:
218         if (r)
219                 condlog(0, "%s: error getting map status string", name);
220
221         dm_task_destroy(dmt);
222         return r;
223 }
224
225 extern int
226 dm_type(char * name, char * type)
227 {
228         int r = 0;
229         struct dm_task *dmt;
230         void *next = NULL;
231         uint64_t start, length;
232         char *target_type = NULL;
233         char *params;
234
235         if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
236                 return 0;
237
238         if (!dm_task_set_name(dmt, name))
239                 goto out;
240
241         dm_task_no_open_count(dmt);
242
243         if (!dm_task_run(dmt))
244                 goto out;
245
246         /* Fetch 1st target */
247         next = dm_get_next_target(dmt, next, &start, &length,
248                                   &target_type, &params);
249
250         if (0 == strcmp(target_type, type))
251                 r = 1;
252
253 out:
254         dm_task_destroy(dmt);
255         return r;
256 }
257
258 static int
259 dm_dev_t (char * mapname, char * dev_t, int len)
260 {
261         int r = 1;
262         struct dm_task *dmt;
263         struct dm_info info;
264
265         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
266                 return 0;
267
268         if (!dm_task_set_name(dmt, mapname))
269                 goto out;
270
271         if (!dm_task_run(dmt))
272                 goto out;
273
274         if (!dm_task_get_info(dmt, &info))
275                 goto out;
276
277         r = info.open_count;
278         if (snprintf(dev_t, len, "%i:%i", info.major, info.minor) > len)
279                     goto out;
280
281         r = 0;
282 out:
283         dm_task_destroy(dmt);
284         return r;
285 }
286         
287 int
288 dm_get_opencount (char * mapname)
289 {
290         int r = -1;
291         struct dm_task *dmt;
292         struct dm_info info;
293
294         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
295                 return 0;
296
297         if (!dm_task_set_name(dmt, mapname))
298                 goto out;
299
300         if (!dm_task_run(dmt))
301                 goto out;
302
303         if (!dm_task_get_info(dmt, &info))
304                 goto out;
305
306         r = info.open_count;
307 out:
308         dm_task_destroy(dmt);
309         return r;
310 }
311         
312 int
313 dm_get_minor (char * mapname)
314 {
315         int r = -1;
316         struct dm_task *dmt;
317         struct dm_info info;
318
319         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
320                 return 0;
321
322         if (!dm_task_set_name(dmt, mapname))
323                 goto out;
324
325         if (!dm_task_run(dmt))
326                 goto out;
327
328         if (!dm_task_get_info(dmt, &info))
329                 goto out;
330
331         r = info.minor;
332 out:
333         dm_task_destroy(dmt);
334         return r;
335 }
336         
337 extern int
338 dm_flush_map (char * mapname, char * type)
339 {
340         int r;
341
342         if (!dm_map_present(mapname))
343                 return 0;
344
345         if (!dm_type(mapname, type))
346                 return 1;
347
348         if (dm_remove_partmaps(mapname))
349                 return 1;
350
351         if (dm_get_opencount(mapname))
352                 return 1;
353
354         r = dm_simplecmd(DM_DEVICE_REMOVE, mapname);
355
356         if (r) {
357                 condlog(4, "multipath map %s removed", mapname);
358                 return 0;
359         }
360         return 1;
361 }
362
363 extern int
364 dm_flush_maps (char * type)
365 {
366         int r = 0;
367         struct dm_task *dmt;
368         struct dm_names *names;
369         unsigned next = 0;
370
371         if (!(dmt = dm_task_create (DM_DEVICE_LIST)))
372                 return 0;
373
374         dm_task_no_open_count(dmt);
375
376         if (!dm_task_run (dmt))
377                 goto out;
378
379         if (!(names = dm_task_get_names (dmt)))
380                 goto out;
381
382         if (!names->dev)
383                 goto out;
384
385         do {
386                 r += dm_flush_map(names->name, type);
387                 next = names->next;
388                 names = (void *) names + next;
389         } while (next);
390
391         out:
392         dm_task_destroy (dmt);
393         return r;
394 }
395
396 int
397 dm_fail_path(char * mapname, char * path)
398 {
399         int r = 1;
400         struct dm_task *dmt;
401         char str[32];
402
403         if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
404                 return 1;
405
406         if (!dm_task_set_name(dmt, mapname))
407                 goto out;
408
409         if (!dm_task_set_sector(dmt, 0))
410                 goto out;
411
412         if (snprintf(str, 32, "fail_path %s\n", path) > 32)
413                 goto out;
414
415         if (!dm_task_set_message(dmt, str))
416                 goto out;
417
418         dm_task_no_open_count(dmt);
419
420         if (!dm_task_run(dmt))
421                 goto out;
422
423         r = 0;
424 out:
425         dm_task_destroy(dmt);
426         return r;
427 }
428
429 int
430 dm_reinstate(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, "reinstate_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 static int
463 dm_groupmsg (char * msg, char * mapname, int index)
464 {
465         int r = 0;
466         struct dm_task *dmt;
467         char str[24];
468
469         if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
470                 return 0;
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         snprintf(str, 24, "%s_group %i\n", msg, index);
479
480         if (!dm_task_set_message(dmt, str))
481                 goto out;
482
483         dm_task_no_open_count(dmt);
484
485         if (!dm_task_run(dmt))
486                 goto out;
487
488         condlog(3, "message %s 0 %s", mapname, str);
489         r = 1;
490
491         out:
492         if (!r)
493                 condlog(3, "message %s 0 %s failed", mapname, str);
494
495         dm_task_destroy(dmt);
496
497         return r;
498 }
499
500 int
501 dm_switchgroup(char * mapname, int index)
502 {
503         return dm_groupmsg("switch", mapname,index);
504 }
505
506 int
507 dm_enablegroup(char * mapname, int index)
508 {
509         return dm_groupmsg("enable", mapname,index);
510 }
511
512 int
513 dm_disablegroup(char * mapname, int index)
514 {
515         return dm_groupmsg("disable", mapname,index);
516 }
517
518 int
519 dm_get_maps (vector mp, char * type)
520 {
521         struct multipath * mpp;
522         int r = 1;
523         struct dm_task *dmt;
524         struct dm_names *names;
525         unsigned next = 0;
526
527         if (!type || !mp)
528                 return 1;
529
530         if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
531                 return 1;
532
533         dm_task_no_open_count(dmt);
534
535         if (!dm_task_run(dmt))
536                 goto out;
537
538         if (!(names = dm_task_get_names(dmt)))
539                 goto out;
540
541         if (!names->dev) {
542                 r = 0; /* this is perfectly valid */
543                 goto out;
544         }
545
546         do {
547                 if (dm_type(names->name, type)) {
548                         mpp = alloc_multipath();
549
550                         if (!mpp)
551                                 goto out;
552
553                         if (dm_get_map(names->name, &mpp->size, mpp->params))
554                                 goto out1;
555
556                         if (dm_get_status(names->name, mpp->status))
557                                 goto out1;
558
559                         mpp->alias = MALLOC(strlen(names->name) + 1);
560
561                         if (!mpp->alias)
562                                 goto out1;
563
564                         strncat(mpp->alias, names->name, strlen(names->name));
565
566                         if (!vector_alloc_slot(mp))
567                                 goto out1;
568                         
569                         vector_set_slot(mp, mpp);
570                         mpp = NULL;
571                 }
572                 next = names->next;
573                 names = (void *) names + next;
574         } while (next);
575
576         r = 0;
577         goto out;
578 out1:
579         free_multipath(mpp, KEEP_PATHS);
580 out:
581         dm_task_destroy (dmt);
582         return r;
583 }
584
585 int
586 dm_geteventnr (char *name)
587 {
588         struct dm_task *dmt;
589         struct dm_info info;
590
591         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
592                 return 0;
593
594         if (!dm_task_set_name(dmt, name))
595                 goto out;
596
597         dm_task_no_open_count(dmt);
598
599         if (!dm_task_run(dmt))
600                 goto out;
601
602         if (!dm_task_get_info(dmt, &info)) {
603                 info.event_nr = 0;
604                 goto out;
605         }
606
607         if (!info.exists) {
608                 info.event_nr = 0;
609                 goto out;
610         }
611
612 out:
613         dm_task_destroy(dmt);
614
615         return info.event_nr;
616 }
617
618 char *
619 dm_mapname(int major, int minor)
620 {
621         char * response;
622         struct dm_task *dmt;
623         int r;
624         int loop = MAX_WAIT * LOOPS_PER_SEC;
625
626         if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
627                 return NULL;
628
629         if (!dm_task_set_major(dmt, major) ||
630             !dm_task_set_minor(dmt, minor))
631                 goto bad;
632
633         dm_task_no_open_count(dmt);
634
635         /*
636          * device map might not be ready when we get here from
637          * daemon uev_trigger -> uev_add_map
638          */
639         while (--loop) {
640                 dm_shut_log();
641                 r = dm_task_run(dmt);
642                 dm_restore_log();
643
644                 if (r)
645                         break;
646
647                 usleep(1000 * 1000 / LOOPS_PER_SEC);
648         }
649
650         if (!r) {
651                 condlog(0, "%i:%i: timeout fetching map name", major, minor);
652                 goto bad;
653         }
654
655         response = STRDUP((char *)dm_task_get_name(dmt));
656         dm_task_destroy(dmt);
657         return response;
658 bad:
659         dm_task_destroy(dmt);
660         condlog(0, "%i:%i: error fetching map name", major, minor);
661         return NULL;
662 }
663
664 int
665 dm_remove_partmaps (char * mapname)
666 {
667         struct dm_task *dmt;
668         struct dm_names *names;
669         unsigned next = 0;
670         char params[PARAMS_SIZE];
671         unsigned long long size;
672         char dev_t[32];
673         int r = 1;
674
675         if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
676                 return 1;
677
678         dm_task_no_open_count(dmt);
679
680         if (!dm_task_run(dmt))
681                 goto out;
682
683         if (!(names = dm_task_get_names(dmt)))
684                 goto out;
685
686         if (!names->dev) {
687                 r = 0; /* this is perfectly valid */
688                 goto out;
689         }
690
691         if (dm_dev_t(mapname, &dev_t[0], 32))
692                 goto out;
693
694         do {
695                 if (
696                     /*
697                      * if devmap target is "linear"
698                      */
699                     dm_type(names->name, "linear") &&
700
701                     /*
702                      * and the multipath mapname and the part mapname start
703                      * the same
704                      */
705                     !strncmp(names->name, mapname, strlen(mapname)) &&
706
707                     /*
708                      * and the opencount is 0 for us to allow removal
709                      */
710                     !dm_get_opencount(names->name) &&
711
712                     /*
713                      * and we can fetch the map table from the kernel
714                      */
715                     !dm_get_map(names->name, &size, &params[0]) &&
716
717                     /*
718                      * and the table maps over the multipath map
719                      */
720                     strstr(params, dev_t)
721                    ) {
722                                 /*
723                                  * then it's a kpartx generated partition.
724                                  * remove it.
725                                  */
726                                 condlog(4, "partition map %s removed",
727                                         names->name);
728                                 dm_simplecmd(DM_DEVICE_REMOVE, names->name);
729                    }
730
731                 next = names->next;
732                 names = (void *) names + next;
733         } while (next);
734
735         r = 0;
736 out:
737         dm_task_destroy (dmt);
738         return r;
739 }
740
741 #if 0
742 int
743 dm_rename (char * old, char * new)
744 {
745         int r = 1;
746         struct dm_task *dmt;
747
748         if (!(dmt = dm_task_create(DM_DEVICE_RENAME)))
749                 return 0;
750
751         if (!dm_task_set_name(dmt, old))
752                 goto out;
753
754         if (!dm_task_set_newname(dmt, new))
755                 goto out;
756         
757         dm_task_no_open_count(dmt);
758
759         if (!dm_task_run(dmt))
760                 goto out;
761
762         r = 0;
763 out:
764         dm_task_destroy(dmt);
765         return r;
766 }
767 #endif