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