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