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