69f475ca180002fbc524e5b46d2953dbdc77f914
[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 <stdarg.h>
10 #include <string.h>
11 #include <libdevmapper.h>
12 #include <ctype.h>
13 #include <unistd.h>
14 #include <errno.h>
15
16 #include "checkers.h"
17 #include "vector.h"
18 #include "structs.h"
19 #include "debug.h"
20 #include "memory.h"
21 #include "devmapper.h"
22 #include "config.h"
23 #include "sysfs.h"
24
25 #include "log_pthread.h"
26 #include <sys/types.h>
27 #include <time.h>
28
29 #define MAX_WAIT 5
30 #define LOOPS_PER_SEC 5
31
32 #define UUID_PREFIX "mpath-"
33 #define UUID_PREFIX_LEN 6
34
35 #ifndef LIBDM_API_COOKIE
36 static inline int dm_task_set_cookie(struct dm_task *dmt, uint32_t *c, int a)
37 {
38         return 1;
39 }
40
41 void udev_wait(unsigned int c)
42 {
43 }
44
45 void udev_set_sync_support(int c)
46 {
47 }
48 #else
49 void udev_wait(unsigned int c)
50 {
51         dm_udev_wait(c);
52 }
53
54 void udev_set_sync_support(int c)
55 {
56         dm_udev_set_sync_support(c);
57 }
58 #endif
59
60 static void
61 dm_write_log (int level, const char *file, int line, const char *f, ...)
62 {
63         va_list ap;
64         int thres;
65
66         if (level > 6)
67                 level = 6;
68
69         thres = (conf) ? conf->verbosity : 0;
70         if (thres <= 3 || level > thres)
71                 return;
72
73         va_start(ap, f);
74         if (!logsink) {
75                 time_t t = time(NULL);
76                 struct tm *tb = localtime(&t);
77                 char buff[16];
78
79                 strftime(buff, sizeof(buff), "%b %d %H:%M:%S", tb);
80                 buff[sizeof(buff)-1] = '\0';
81
82                 fprintf(stdout, "%s | ", buff);
83                 fprintf(stdout, "libdevmapper: %s(%i): ", file, line);
84                 vfprintf(stdout, f, ap);
85                 fprintf(stdout, "\n");
86         } else {
87                 condlog(level, "libdevmapper: %s(%i): ", file, line);
88                 log_safe(level + 3, f, ap);
89         }
90         va_end(ap);
91
92         return;
93 }
94
95 extern void
96 dm_init(void) {
97         dm_log_init(&dm_write_log);
98         dm_log_init_verbose(conf ? conf->verbosity + 3 : 0);
99 }
100
101 static int
102 dm_lib_prereq (void)
103 {
104         char version[64];
105         int v[3];
106 #ifdef LIBDM_API_COOKIE
107         int minv[3] = {1, 2, 38};
108 #else
109         int minv[3] = {1, 2, 8};
110 #endif
111
112         dm_get_library_version(version, sizeof(version));
113         condlog(3, "libdevmapper version %s", version);
114         sscanf(version, "%d.%d.%d ", &v[0], &v[1], &v[2]);
115
116         if VERSION_GE(v, minv)
117                 return 0;
118         condlog(0, "libdevmapper version must be >= %d.%.2d.%.2d",
119                 minv[0], minv[1], minv[2]);
120         return 1;
121 }
122
123 int
124 dm_drv_version (unsigned int * version, char * str)
125 {
126         int r = 2;
127         struct dm_task *dmt;
128         struct dm_versions *target;
129         struct dm_versions *last_target;
130         unsigned int *v;
131
132         version[0] = 0;
133         version[1] = 0;
134         version[2] = 0;
135
136         if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
137                 return 1;
138
139         dm_task_no_open_count(dmt);
140
141         if (!dm_task_run(dmt)) {
142                 condlog(0, "Can not communicate with kernel DM");
143                 goto out;
144         }
145         target = dm_task_get_versions(dmt);
146
147         do {
148                 last_target = target;
149                 if (!strncmp(str, target->name, strlen(str))) {
150                         r = 1;
151                         break;
152                 }
153                 target = (void *) target + target->next;
154         } while (last_target != target);
155
156         if (r == 2) {
157                 condlog(0, "DM %s kernel driver not loaded", str);
158                 goto out;
159         }
160         v = target->version;
161         version[0] = v[0];
162         version[1] = v[1];
163         version[2] = v[2];
164         r = 0;
165 out:
166         dm_task_destroy(dmt);
167         return r;
168 }
169
170 static int
171 dm_drv_prereq (void)
172 {
173         unsigned int minv[3] = {1, 0, 3};
174         unsigned int version[3] = {0, 0, 0};
175         unsigned int * v = version;
176
177         if (dm_drv_version(v, TGT_MPATH)) {
178                 /* in doubt return not capable */
179                 return 1;
180         }
181
182         /* test request based multipath capability */
183         condlog(3, "DM multipath kernel driver v%u.%u.%u",
184                 v[0], v[1], v[2]);
185
186         if VERSION_GE(v, minv)
187                 return 0;
188
189         condlog(0, "DM multipath kernel driver must be >= v%u.%u.%u",
190                 minv[0], minv[1], minv[2]);
191         return 1;
192 }
193
194 extern int
195 dm_prereq (void)
196 {
197         if (dm_lib_prereq())
198                 return 1;
199         return dm_drv_prereq();
200 }
201
202 static int
203 dm_simplecmd (int task, const char *name, int no_flush, int need_sync) {
204         int r = 0;
205         int udev_wait_flag = (need_sync && (task == DM_DEVICE_RESUME ||
206                                             task == DM_DEVICE_REMOVE));
207         struct dm_task *dmt;
208
209         if (!(dmt = dm_task_create (task)))
210                 return 0;
211
212         if (!dm_task_set_name (dmt, name))
213                 goto out;
214
215         dm_task_no_open_count(dmt);
216         dm_task_skip_lockfs(dmt);       /* for DM_DEVICE_RESUME */
217 #ifdef LIBDM_API_FLUSH
218         if (no_flush)
219                 dm_task_no_flush(dmt);          /* for DM_DEVICE_SUSPEND/RESUME */
220 #endif
221
222         if (udev_wait_flag && !dm_task_set_cookie(dmt, &conf->cookie, (conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0))
223                 goto out;
224         r = dm_task_run (dmt);
225
226         out:
227         dm_task_destroy (dmt);
228         return r;
229 }
230
231 extern int
232 dm_simplecmd_flush (int task, const char *name, int needsync) {
233         return dm_simplecmd(task, name, 0, needsync);
234 }
235
236 extern int
237 dm_simplecmd_noflush (int task, const char *name) {
238         return dm_simplecmd(task, name, 1, 1);
239 }
240
241 extern int
242 dm_addmap (int task, const char *target, struct multipath *mpp, char * params,
243            int use_uuid, int ro) {
244         int r = 0;
245         struct dm_task *dmt;
246         char *prefixed_uuid = NULL;
247
248         if (!(dmt = dm_task_create (task)))
249                 return 0;
250
251         if (!dm_task_set_name (dmt, mpp->alias))
252                 goto addout;
253
254         if (!dm_task_add_target (dmt, 0, mpp->size, target, params))
255                 goto addout;
256
257         if (ro)
258                 dm_task_set_ro(dmt);
259
260         if (use_uuid && strlen(mpp->wwid) > 0){
261                 prefixed_uuid = MALLOC(UUID_PREFIX_LEN + strlen(mpp->wwid) + 1);
262                 if (!prefixed_uuid) {
263                         condlog(0, "cannot create prefixed uuid : %s",
264                                 strerror(errno));
265                         goto addout;
266                 }
267                 sprintf(prefixed_uuid, UUID_PREFIX "%s", mpp->wwid);
268                 if (!dm_task_set_uuid(dmt, prefixed_uuid))
269                         goto freeout;
270         }
271
272         if (mpp->attribute_flags & (1 << ATTR_MODE) &&
273             !dm_task_set_mode(dmt, mpp->mode))
274                 goto freeout;
275         if (mpp->attribute_flags & (1 << ATTR_UID) &&
276             !dm_task_set_uid(dmt, mpp->uid))
277                 goto freeout;
278         if (mpp->attribute_flags & (1 << ATTR_GID) &&
279             !dm_task_set_gid(dmt, mpp->gid))
280                 goto freeout;
281         condlog(4, "%s: addmap [0 %llu %s %s]", mpp->alias, mpp->size,
282                 target, params);
283
284         dm_task_no_open_count(dmt);
285
286         if (task == DM_DEVICE_CREATE &&
287             !dm_task_set_cookie(dmt, &conf->cookie, (conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0))
288                 goto freeout;
289         r = dm_task_run (dmt);
290
291         freeout:
292         if (prefixed_uuid)
293                 FREE(prefixed_uuid);
294
295         addout:
296         dm_task_destroy (dmt);
297
298         return r;
299 }
300
301 static int
302 _dm_addmap_create (struct multipath *mpp, char * params, int ro) {
303         int r;
304         r = dm_addmap(DM_DEVICE_CREATE, TGT_MPATH, mpp, params, 1, ro);
305         /*
306          * DM_DEVICE_CREATE is actually DM_DEV_CREATE + DM_TABLE_LOAD.
307          * Failing the second part leaves an empty map. Clean it up.
308          */
309         if (!r && dm_map_present(mpp->alias)) {
310                 condlog(3, "%s: failed to load map (a path might be in use)",
311                         mpp->alias);
312                 dm_flush_map_nosync(mpp->alias);
313         }
314         return r;
315 }
316
317 #define ADDMAP_RW 0
318 #define ADDMAP_RO 1
319
320 extern int
321 dm_addmap_create (struct multipath *mpp, char *params) {
322         return _dm_addmap_create(mpp, params, ADDMAP_RW);
323 }
324
325 extern int
326 dm_addmap_create_ro (struct multipath *mpp, char *params) {
327         return _dm_addmap_create(mpp, params, ADDMAP_RO);
328 }
329
330 extern int
331 dm_addmap_reload (struct multipath *mpp, char *params) {
332         return dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, 0, ADDMAP_RW);
333 }
334
335 extern int
336 dm_addmap_reload_ro (struct multipath *mpp, char *params) {
337         return dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, 0, ADDMAP_RO);
338 }
339
340 extern int
341 dm_map_present (const char * str)
342 {
343         int r = 0;
344         struct dm_task *dmt;
345         struct dm_info info;
346
347         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
348                 return 0;
349
350         if (!dm_task_set_name(dmt, str))
351                 goto out;
352
353         dm_task_no_open_count(dmt);
354
355         if (!dm_task_run(dmt))
356                 goto out;
357
358         if (!dm_task_get_info(dmt, &info))
359                 goto out;
360
361         if (info.exists)
362                 r = 1;
363 out:
364         dm_task_destroy(dmt);
365         return r;
366 }
367
368 extern int
369 dm_get_map(char * name, unsigned long long * size, char * outparams)
370 {
371         int r = 1;
372         struct dm_task *dmt;
373         void *next = NULL;
374         uint64_t start, length;
375         char *target_type = NULL;
376         char *params = NULL;
377
378         if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
379                 return 1;
380
381         if (!dm_task_set_name(dmt, name))
382                 goto out;
383
384         dm_task_no_open_count(dmt);
385
386         if (!dm_task_run(dmt))
387                 goto out;
388
389         /* Fetch 1st target */
390         next = dm_get_next_target(dmt, next, &start, &length,
391                                   &target_type, &params);
392
393         if (size)
394                 *size = length;
395
396         if (!outparams) {
397                 r = 0;
398                 goto out;
399         }
400         if (snprintf(outparams, PARAMS_SIZE, "%s", params) <= PARAMS_SIZE)
401                 r = 0;
402 out:
403         dm_task_destroy(dmt);
404         return r;
405 }
406
407 static int
408 dm_get_prefixed_uuid(const char *name, char *uuid)
409 {
410         struct dm_task *dmt;
411         const char *uuidtmp;
412         int r = 1;
413
414         dmt = dm_task_create(DM_DEVICE_INFO);
415         if (!dmt)
416                 return 1;
417
418         if (!dm_task_set_name (dmt, name))
419                 goto uuidout;
420
421         if (!dm_task_run(dmt))
422                 goto uuidout;
423
424         uuidtmp = dm_task_get_uuid(dmt);
425         if (uuidtmp)
426                 strcpy(uuid, uuidtmp);
427         else
428                 uuid[0] = '\0';
429
430         r = 0;
431 uuidout:
432         dm_task_destroy(dmt);
433         return r;
434 }
435
436 extern int
437 dm_get_uuid(char *name, char *uuid)
438 {
439         char uuidtmp[WWID_SIZE];
440
441         if (dm_get_prefixed_uuid(name, uuidtmp))
442                 return 1;
443
444         if (!strncmp(uuidtmp, UUID_PREFIX, UUID_PREFIX_LEN))
445                 strcpy(uuid, uuidtmp + UUID_PREFIX_LEN);
446         else
447                 strcpy(uuid, uuidtmp);
448
449         return 0;
450 }
451
452 /*
453  * returns:
454  *    0 : if both uuids end with same suffix which starts with UUID_PREFIX
455  *    1 : otherwise
456  */
457 int
458 dm_compare_uuid(const char* mapname1, const char* mapname2)
459 {
460         char *p1, *p2;
461         char uuid1[WWID_SIZE], uuid2[WWID_SIZE];
462
463         if (dm_get_prefixed_uuid(mapname1, uuid1))
464                 return 1;
465
466         if (dm_get_prefixed_uuid(mapname2, uuid2))
467                 return 1;
468
469         p1 = strstr(uuid1, UUID_PREFIX);
470         p2 = strstr(uuid2, UUID_PREFIX);
471         if (p1 && p2 && !strcmp(p1, p2))
472                 return 0;
473
474         return 1;
475 }
476
477 extern int
478 dm_get_status(char * name, char * outstatus)
479 {
480         int r = 1;
481         struct dm_task *dmt;
482         void *next = NULL;
483         uint64_t start, length;
484         char *target_type;
485         char *status;
486
487         if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
488                 return 1;
489
490         if (!dm_task_set_name(dmt, name))
491                 goto out;
492
493         dm_task_no_open_count(dmt);
494
495         if (!dm_task_run(dmt))
496                 goto out;
497
498         /* Fetch 1st target */
499         next = dm_get_next_target(dmt, next, &start, &length,
500                                   &target_type, &status);
501
502         if (snprintf(outstatus, PARAMS_SIZE, "%s", status) <= PARAMS_SIZE)
503                 r = 0;
504 out:
505         if (r)
506                 condlog(0, "%s: error getting map status string", name);
507
508         dm_task_destroy(dmt);
509         return r;
510 }
511
512 /*
513  * returns:
514  *    1 : match
515  *    0 : no match
516  *   -1 : empty map
517  */
518 extern int
519 dm_type(const char * name, char * type)
520 {
521         int r = 0;
522         struct dm_task *dmt;
523         void *next = NULL;
524         uint64_t start, length;
525         char *target_type = NULL;
526         char *params;
527
528         if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
529                 return 0;
530
531         if (!dm_task_set_name(dmt, name))
532                 goto out;
533
534         dm_task_no_open_count(dmt);
535
536         if (!dm_task_run(dmt))
537                 goto out;
538
539         /* Fetch 1st target */
540         next = dm_get_next_target(dmt, next, &start, &length,
541                                   &target_type, &params);
542
543         if (!target_type)
544                 r = -1;
545         else if (!strcmp(target_type, type))
546                 r = 1;
547
548 out:
549         dm_task_destroy(dmt);
550         return r;
551 }
552
553 static int
554 dm_dev_t (const char * mapname, char * dev_t, int len)
555 {
556         int r = 1;
557         struct dm_task *dmt;
558         struct dm_info info;
559
560         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
561                 return 0;
562
563         if (!dm_task_set_name(dmt, mapname))
564                 goto out;
565
566         if (!dm_task_run(dmt))
567                 goto out;
568
569         if (!dm_task_get_info(dmt, &info))
570                 goto out;
571
572         r = info.open_count;
573         if (snprintf(dev_t, len, "%i:%i", info.major, info.minor) > len)
574                     goto out;
575
576         r = 0;
577 out:
578         dm_task_destroy(dmt);
579         return r;
580 }
581
582 int
583 dm_get_opencount (const char * mapname)
584 {
585         int r = -1;
586         struct dm_task *dmt;
587         struct dm_info info;
588
589         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
590                 return 0;
591
592         if (!dm_task_set_name(dmt, mapname))
593                 goto out;
594
595         if (!dm_task_run(dmt))
596                 goto out;
597
598         if (!dm_task_get_info(dmt, &info))
599                 goto out;
600
601         r = info.open_count;
602 out:
603         dm_task_destroy(dmt);
604         return r;
605 }
606
607 int
608 dm_get_major (char * mapname)
609 {
610         int r = -1;
611         struct dm_task *dmt;
612         struct dm_info info;
613
614         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
615                 return 0;
616
617         if (!dm_task_set_name(dmt, mapname))
618                 goto out;
619
620         if (!dm_task_run(dmt))
621                 goto out;
622
623         if (!dm_task_get_info(dmt, &info))
624                 goto out;
625
626         r = info.major;
627 out:
628         dm_task_destroy(dmt);
629         return r;
630 }
631
632 int
633 dm_get_minor (char * mapname)
634 {
635         int r = -1;
636         struct dm_task *dmt;
637         struct dm_info info;
638
639         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
640                 return 0;
641
642         if (!dm_task_set_name(dmt, mapname))
643                 goto out;
644
645         if (!dm_task_run(dmt))
646                 goto out;
647
648         if (!dm_task_get_info(dmt, &info))
649                 goto out;
650
651         r = info.minor;
652 out:
653         dm_task_destroy(dmt);
654         return r;
655 }
656
657 extern int
658 _dm_flush_map (const char * mapname, int need_sync)
659 {
660         int r;
661
662         if (!dm_map_present(mapname))
663                 return 0;
664
665         if (dm_type(mapname, TGT_MPATH) <= 0)
666                 return 0; /* nothing to do */
667
668         if (dm_remove_partmaps(mapname, need_sync))
669                 return 1;
670
671         if (dm_get_opencount(mapname)) {
672                 condlog(2, "%s: map in use", mapname);
673                 return 1;
674         }
675
676         r = dm_simplecmd_flush(DM_DEVICE_REMOVE, mapname, need_sync);
677
678         if (r) {
679                 condlog(4, "multipath map %s removed", mapname);
680                 return 0;
681         }
682         return 1;
683 }
684
685 extern int
686 dm_suspend_and_flush_map (const char * mapname)
687 {
688         int s;
689
690         if (!dm_map_present(mapname))
691                 return 0;
692
693         if (dm_type(mapname, TGT_MPATH) <= 0)
694                 return 0; /* nothing to do */
695
696         s = dm_queue_if_no_path((char *)mapname, 0);
697         if (!s)
698                 s = dm_simplecmd_flush(DM_DEVICE_SUSPEND, mapname, 0);
699
700         if (!dm_flush_map(mapname)) {
701                 condlog(4, "multipath map %s removed", mapname);
702                 return 0;
703         }
704         condlog(2, "failed to remove multipath map %s", mapname);
705         dm_simplecmd_noflush(DM_DEVICE_RESUME, mapname);
706         return 1;
707 }
708
709 extern int
710 dm_flush_maps (void)
711 {
712         int r = 0;
713         struct dm_task *dmt;
714         struct dm_names *names;
715         unsigned next = 0;
716
717         if (!(dmt = dm_task_create (DM_DEVICE_LIST)))
718                 return 0;
719
720         dm_task_no_open_count(dmt);
721
722         if (!dm_task_run (dmt))
723                 goto out;
724
725         if (!(names = dm_task_get_names (dmt)))
726                 goto out;
727
728         if (!names->dev)
729                 goto out;
730
731         do {
732                 r |= dm_suspend_and_flush_map(names->name);
733                 next = names->next;
734                 names = (void *) names + next;
735         } while (next);
736
737         out:
738         dm_task_destroy (dmt);
739         return r;
740 }
741
742 int
743 dm_message(char * mapname, char * message)
744 {
745         int r = 1;
746         struct dm_task *dmt;
747
748         if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
749                 return 1;
750
751         if (!dm_task_set_name(dmt, mapname))
752                 goto out;
753
754         if (!dm_task_set_sector(dmt, 0))
755                 goto out;
756
757         if (!dm_task_set_message(dmt, message))
758                 goto out;
759
760         dm_task_no_open_count(dmt);
761
762         if (!dm_task_run(dmt))
763                 goto out;
764
765         r = 0;
766 out:
767         if (r)
768                 condlog(0, "DM message failed [%s]", message);
769
770         dm_task_destroy(dmt);
771         return r;
772 }
773
774 int
775 dm_fail_path(char * mapname, char * path)
776 {
777         char message[32];
778
779         if (snprintf(message, 32, "fail_path %s", path) > 32)
780                 return 1;
781
782         return dm_message(mapname, message);
783 }
784
785 int
786 dm_reinstate_path(char * mapname, char * path)
787 {
788         char message[32];
789
790         if (snprintf(message, 32, "reinstate_path %s", path) > 32)
791                 return 1;
792
793         return dm_message(mapname, message);
794 }
795
796 int
797 dm_queue_if_no_path(char *mapname, int enable)
798 {
799         char *message;
800
801         if (enable)
802                 message = "queue_if_no_path";
803         else
804                 message = "fail_if_no_path";
805
806         return dm_message(mapname, message);
807 }
808
809 static int
810 dm_groupmsg (char * msg, char * mapname, int index)
811 {
812         char message[32];
813
814         if (snprintf(message, 32, "%s_group %i", msg, index) > 32)
815                 return 1;
816
817         return dm_message(mapname, message);
818 }
819
820 int
821 dm_switchgroup(char * mapname, int index)
822 {
823         return dm_groupmsg("switch", mapname, index);
824 }
825
826 int
827 dm_enablegroup(char * mapname, int index)
828 {
829         return dm_groupmsg("enable", mapname, index);
830 }
831
832 int
833 dm_disablegroup(char * mapname, int index)
834 {
835         return dm_groupmsg("disable", mapname, index);
836 }
837
838 int
839 dm_get_maps (vector mp)
840 {
841         struct multipath * mpp;
842         int r = 1;
843         int info;
844         struct dm_task *dmt;
845         struct dm_names *names;
846         unsigned next = 0;
847
848         if (!mp)
849                 return 1;
850
851         if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
852                 return 1;
853
854         dm_task_no_open_count(dmt);
855
856         if (!dm_task_run(dmt))
857                 goto out;
858
859         if (!(names = dm_task_get_names(dmt)))
860                 goto out;
861
862         if (!names->dev) {
863                 r = 0; /* this is perfectly valid */
864                 goto out;
865         }
866
867         do {
868                 info = dm_type(names->name, TGT_MPATH);
869
870                 if (info <= 0)
871                         goto next;
872
873                 mpp = alloc_multipath();
874
875                 if (!mpp)
876                         goto out;
877
878                 mpp->alias = STRDUP(names->name);
879
880                 if (!mpp->alias)
881                         goto out1;
882
883                 if (info > 0) {
884                         if (dm_get_map(names->name, &mpp->size, NULL))
885                                 goto out1;
886
887                         dm_get_uuid(names->name, mpp->wwid);
888                         dm_get_info(names->name, &mpp->dmi);
889                 }
890
891                 if (!vector_alloc_slot(mp))
892                         goto out1;
893
894                 vector_set_slot(mp, mpp);
895                 mpp = NULL;
896 next:
897                 next = names->next;
898                 names = (void *) names + next;
899         } while (next);
900
901         r = 0;
902         goto out;
903 out1:
904         free_multipath(mpp, KEEP_PATHS);
905 out:
906         dm_task_destroy (dmt);
907         return r;
908 }
909
910 extern char *
911 dm_get_name(char *uuid)
912 {
913         struct dm_task *dmt;
914         struct dm_info info;
915         char *prefixed_uuid, *name = NULL;
916         const char *nametmp;
917
918         dmt = dm_task_create(DM_DEVICE_INFO);
919         if (!dmt)
920                 return NULL;
921
922         prefixed_uuid = MALLOC(UUID_PREFIX_LEN + strlen(uuid) + 1);
923         if (!prefixed_uuid) {
924                 condlog(0, "cannot create prefixed uuid : %s",
925                         strerror(errno));
926                 goto freeout;
927         }
928         sprintf(prefixed_uuid, UUID_PREFIX "%s", uuid);
929         if (!dm_task_set_uuid(dmt, prefixed_uuid))
930                 goto freeout;
931
932         if (!dm_task_run(dmt))
933                 goto freeout;
934
935         if (!dm_task_get_info(dmt, &info) || !info.exists)
936                 goto freeout;
937
938         nametmp = dm_task_get_name(dmt);
939         if (nametmp && strlen(nametmp)) {
940                 name = MALLOC(strlen(nametmp) + 1);
941                 if (name)
942                         strcpy(name, nametmp);
943         } else {
944                 condlog(2, "%s: no device-mapper name found", uuid);
945         }
946
947 freeout:
948         if (prefixed_uuid)
949                 FREE(prefixed_uuid);
950         dm_task_destroy(dmt);
951
952         return name;
953 }
954
955 int
956 dm_geteventnr (char *name)
957 {
958         struct dm_task *dmt;
959         struct dm_info info;
960         int event = -1;
961
962         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
963                 return -1;
964
965         if (!dm_task_set_name(dmt, name))
966                 goto out;
967
968         dm_task_no_open_count(dmt);
969
970         if (!dm_task_run(dmt))
971                 goto out;
972
973         if (!dm_task_get_info(dmt, &info))
974                 goto out;
975
976         if (info.exists)
977                 event = info.event_nr;
978
979 out:
980         dm_task_destroy(dmt);
981
982         return event;
983 }
984
985 char *
986 dm_mapname(int major, int minor)
987 {
988         char * response = NULL;
989         const char *map;
990         struct dm_task *dmt;
991         int r;
992         int loop = MAX_WAIT * LOOPS_PER_SEC;
993
994         if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
995                 return NULL;
996
997         if (!dm_task_set_major(dmt, major) ||
998             !dm_task_set_minor(dmt, minor))
999                 goto bad;
1000
1001         dm_task_no_open_count(dmt);
1002
1003         /*
1004          * device map might not be ready when we get here from
1005          * daemon uev_trigger -> uev_add_map
1006          */
1007         while (--loop) {
1008                 r = dm_task_run(dmt);
1009
1010                 if (r)
1011                         break;
1012
1013                 usleep(1000 * 1000 / LOOPS_PER_SEC);
1014         }
1015
1016         if (!r) {
1017                 condlog(0, "%i:%i: timeout fetching map name", major, minor);
1018                 goto bad;
1019         }
1020
1021         map = dm_task_get_name(dmt);
1022         if (map && strlen(map))
1023                 response = STRDUP((char *)dm_task_get_name(dmt));
1024
1025         dm_task_destroy(dmt);
1026         return response;
1027 bad:
1028         dm_task_destroy(dmt);
1029         condlog(0, "%i:%i: error fetching map name", major, minor);
1030         return NULL;
1031 }
1032
1033 int
1034 dm_remove_partmaps (const char * mapname, int need_sync)
1035 {
1036         struct dm_task *dmt;
1037         struct dm_names *names;
1038         unsigned next = 0;
1039         char params[PARAMS_SIZE];
1040         unsigned long long size;
1041         char dev_t[32];
1042         int r = 1;
1043
1044         if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
1045                 return 1;
1046
1047         dm_task_no_open_count(dmt);
1048
1049         if (!dm_task_run(dmt))
1050                 goto out;
1051
1052         if (!(names = dm_task_get_names(dmt)))
1053                 goto out;
1054
1055         if (!names->dev) {
1056                 r = 0; /* this is perfectly valid */
1057                 goto out;
1058         }
1059
1060         if (dm_dev_t(mapname, &dev_t[0], 32))
1061                 goto out;
1062
1063         do {
1064                 if (
1065                     /*
1066                      * if devmap target is "linear"
1067                      */
1068                     (dm_type(names->name, TGT_PART) > 0) &&
1069
1070                     /*
1071                      * and both uuid end with same suffix starting
1072                      * at UUID_PREFIX
1073                      */
1074                     (!dm_compare_uuid(names->name, mapname)) &&
1075
1076                     /*
1077                      * and we can fetch the map table from the kernel
1078                      */
1079                     !dm_get_map(names->name, &size, &params[0]) &&
1080
1081                     /*
1082                      * and the table maps over the multipath map
1083                      */
1084                     strstr(params, dev_t)
1085                    ) {
1086                         /*
1087                          * then it's a kpartx generated partition.
1088                          * remove it.
1089                          */
1090                         /*
1091                          * if the opencount is 0 maybe some other
1092                          * partitions depend on it.
1093                          */
1094                         if (dm_get_opencount(names->name)) {
1095                                 dm_remove_partmaps(names->name, need_sync);
1096                                 if (dm_get_opencount(names->name)) {
1097                                         condlog(2, "%s: map in use",
1098                                                 names->name);
1099                                         goto out;
1100                                 }
1101                         }
1102                         condlog(4, "partition map %s removed",
1103                                 names->name);
1104                         dm_simplecmd_flush(DM_DEVICE_REMOVE, names->name,
1105                                            need_sync);
1106                 }
1107
1108                 next = names->next;
1109                 names = (void *) names + next;
1110         } while (next);
1111
1112         r = 0;
1113 out:
1114         dm_task_destroy (dmt);
1115         return r;
1116 }
1117
1118 static struct dm_info *
1119 alloc_dminfo (void)
1120 {
1121         return MALLOC(sizeof(struct dm_info));
1122 }
1123
1124 int
1125 dm_get_info (char * mapname, struct dm_info ** dmi)
1126 {
1127         int r = 1;
1128         struct dm_task *dmt = NULL;
1129
1130         if (!mapname)
1131                 return 1;
1132
1133         if (!*dmi)
1134                 *dmi = alloc_dminfo();
1135
1136         if (!*dmi)
1137                 return 1;
1138
1139         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
1140                 goto out;
1141
1142         if (!dm_task_set_name(dmt, mapname))
1143                 goto out;
1144
1145         dm_task_no_open_count(dmt);
1146
1147         if (!dm_task_run(dmt))
1148                 goto out;
1149
1150         if (!dm_task_get_info(dmt, *dmi))
1151                 goto out;
1152
1153         r = 0;
1154 out:
1155         if (r) {
1156                 memset(*dmi, 0, sizeof(struct dm_info));
1157                 FREE(*dmi);
1158                 *dmi = NULL;
1159         }
1160
1161         if (dmt)
1162                 dm_task_destroy(dmt);
1163
1164         return r;
1165 }
1166
1167 int
1168 dm_rename_partmaps (char * old, char * new)
1169 {
1170         struct dm_task *dmt;
1171         struct dm_names *names;
1172         unsigned next = 0;
1173         char buff[PARAMS_SIZE];
1174         unsigned long long size;
1175         char dev_t[32];
1176         int r = 1;
1177
1178         if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
1179                 return 1;
1180
1181         dm_task_no_open_count(dmt);
1182
1183         if (!dm_task_run(dmt))
1184                 goto out;
1185
1186         if (!(names = dm_task_get_names(dmt)))
1187                 goto out;
1188
1189         if (!names->dev) {
1190                 r = 0; /* this is perfectly valid */
1191                 goto out;
1192         }
1193
1194         if (dm_dev_t(old, &dev_t[0], 32))
1195                 goto out;
1196
1197         do {
1198                 if (
1199                     /*
1200                      * if devmap target is "linear"
1201                      */
1202                     (dm_type(names->name, TGT_PART) > 0) &&
1203
1204                     /*
1205                      * and the multipath mapname and the part mapname start
1206                      * the same
1207                      */
1208                     !strncmp(names->name, old, strlen(old)) &&
1209
1210                     /*
1211                      * and we can fetch the map table from the kernel
1212                      */
1213                     !dm_get_map(names->name, &size, &buff[0]) &&
1214
1215                     /*
1216                      * and the table maps over the multipath map
1217                      */
1218                     strstr(buff, dev_t)
1219                    ) {
1220                                 /*
1221                                  * then it's a kpartx generated partition.
1222                                  * Rename it.
1223                                  */
1224                                 snprintf(buff, PARAMS_SIZE, "%s%s",
1225                                          new, names->name + strlen(old));
1226                                 dm_rename(names->name, buff);
1227                                 condlog(4, "partition map %s renamed",
1228                                         names->name);
1229                    }
1230
1231                 next = names->next;
1232                 names = (void *) names + next;
1233         } while (next);
1234
1235         r = 0;
1236 out:
1237         dm_task_destroy (dmt);
1238         return r;
1239 }
1240
1241 int
1242 dm_rename (char * old, char * new)
1243 {
1244         int r = 0;
1245         struct dm_task *dmt;
1246
1247         if (dm_rename_partmaps(old, new))
1248                 return r;
1249
1250         if (!(dmt = dm_task_create(DM_DEVICE_RENAME)))
1251                 return r;
1252
1253         if (!dm_task_set_name(dmt, old))
1254                 goto out;
1255
1256         if (!dm_task_set_newname(dmt, new))
1257                 goto out;
1258
1259         dm_task_no_open_count(dmt);
1260
1261         if (!dm_task_set_cookie(dmt, &conf->cookie, (conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0))
1262                 goto out;
1263         if (!dm_task_run(dmt))
1264                 goto out;
1265
1266         r = 1;
1267 out:
1268         dm_task_destroy(dmt);
1269         return r;
1270 }
1271
1272 void dm_reassign_deps(char *table, char *dep, char *newdep)
1273 {
1274         char *p, *n;
1275         char newtable[PARAMS_SIZE];
1276
1277         strcpy(newtable, table);
1278         p = strstr(newtable, dep);
1279         n = table + (p - newtable);
1280         strcpy(n, newdep);
1281         n += strlen(newdep);
1282         p += strlen(dep);
1283         strcat(n, p);
1284 }
1285
1286 int dm_reassign_table(const char *name, char *old, char *new)
1287 {
1288         int r, modified = 0;
1289         uint64_t start, length;
1290         struct dm_task *dmt, *reload_dmt;
1291         char *target, *params = NULL;
1292         char buff[PARAMS_SIZE];
1293         void *next = NULL;
1294
1295         if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
1296                 return 0;
1297
1298         if (!dm_task_set_name(dmt, name))
1299                 goto out;
1300
1301         dm_task_no_open_count(dmt);
1302
1303         if (!dm_task_run(dmt))
1304                 goto out;
1305         if (!(reload_dmt = dm_task_create(DM_DEVICE_RELOAD)))
1306                 goto out;
1307         if (!dm_task_set_name(reload_dmt, name))
1308                 goto out_reload;
1309
1310         do {
1311                 next = dm_get_next_target(dmt, next, &start, &length,
1312                                           &target, &params);
1313                 memset(buff, 0, PARAMS_SIZE);
1314                 strcpy(buff, params);
1315                 if (strcmp(target, TGT_MPATH) && strstr(params, old)) {
1316                         condlog(3, "%s: replace target %s %s",
1317                                 name, target, buff);
1318                         dm_reassign_deps(buff, old, new);
1319                         condlog(3, "%s: with target %s %s",
1320                                 name, target, buff);
1321                         modified++;
1322                 }
1323                 dm_task_add_target(reload_dmt, start, length, target, buff);
1324         } while (next);
1325
1326         if (modified) {
1327                 dm_task_no_open_count(reload_dmt);
1328
1329                 if (!dm_task_run(reload_dmt)) {
1330                         condlog(3, "%s: failed to reassign targets", name);
1331                         goto out_reload;
1332                 }
1333                 dm_simplecmd_noflush(DM_DEVICE_RESUME, name);
1334         }
1335         r = 1;
1336
1337 out_reload:
1338         dm_task_destroy(reload_dmt);
1339 out:
1340         dm_task_destroy(dmt);
1341         return r;
1342 }
1343
1344
1345 /*
1346  * Reassign existing device-mapper table(s) to not use
1347  * the block devices but point to the multipathed
1348  * device instead
1349  */
1350 int dm_reassign(const char *mapname)
1351 {
1352         struct dm_deps *deps;
1353         struct dm_task *dmt;
1354         struct dm_info info;
1355         char dev_t[32], dm_dep[32];
1356         int r = 0, i;
1357
1358         if (dm_dev_t(mapname, &dev_t[0], 32)) {
1359                 condlog(3, "%s: failed to get device number", mapname);
1360                 return 1;
1361         }
1362
1363         if (!(dmt = dm_task_create(DM_DEVICE_DEPS))) {
1364                 condlog(3, "%s: couldn't make dm task", mapname);
1365                 return 0;
1366         }
1367
1368         if (!dm_task_set_name(dmt, mapname))
1369                 goto out;
1370
1371         dm_task_no_open_count(dmt);
1372
1373         if (!dm_task_run(dmt))
1374                 goto out;
1375
1376         if (!dm_task_get_info(dmt, &info))
1377                 goto out;
1378
1379         if (!(deps = dm_task_get_deps(dmt)))
1380                 goto out;
1381
1382         if (!info.exists)
1383                 goto out;
1384
1385         for (i = 0; i < deps->count; i++) {
1386                 sprintf(dm_dep, "%d:%d",
1387                         major(deps->device[i]),
1388                         minor(deps->device[i]));
1389                 sysfs_check_holders(dm_dep, dev_t);
1390         }
1391
1392         dm_task_destroy (dmt);
1393
1394         r = 1;
1395 out:
1396         return r;
1397 }
1398
1399 int dm_setgeometry(struct multipath *mpp)
1400 {
1401         struct dm_task *dmt;
1402         struct path *pp;
1403         char heads[4], sectors[4];
1404         char cylinders[10], start[32];
1405         int r = 0;
1406
1407         if (!mpp)
1408                 return 1;
1409
1410         pp = first_path(mpp);
1411         if (!pp) {
1412                 condlog(3, "%s: no path for geometry", mpp->alias);
1413                 return 1;
1414         }
1415         if (pp->geom.cylinders == 0 ||
1416             pp->geom.heads == 0 ||
1417             pp->geom.sectors == 0) {
1418                 condlog(3, "%s: invalid geometry on %s", mpp->alias, pp->dev);
1419                 return 1;
1420         }
1421
1422         if (!(dmt = dm_task_create(DM_DEVICE_SET_GEOMETRY)))
1423                 return 0;
1424
1425         if (!dm_task_set_name(dmt, mpp->alias))
1426                 goto out;
1427
1428         dm_task_no_open_count(dmt);
1429
1430         /* What a sick interface ... */
1431         snprintf(heads, 4, "%u", pp->geom.heads);
1432         snprintf(sectors, 4, "%u", pp->geom.sectors);
1433         snprintf(cylinders, 10, "%u", pp->geom.cylinders);
1434         snprintf(start, 32, "%lu", pp->geom.start);
1435         if (!dm_task_set_geometry(dmt, cylinders, heads, sectors, start)) {
1436                 condlog(3, "%s: Failed to set geometry", mpp->alias);
1437                 goto out;
1438         }
1439
1440         r = dm_task_run(dmt);
1441 out:
1442         dm_task_destroy(dmt);
1443
1444         return r;
1445 }