xref: /dragonfly/contrib/lvm2/dist/libdm/libdm-deptree.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
1 /*        $NetBSD: libdm-deptree.c,v 1.4 2009/12/02 00:58:03 haad Exp $         */
2 
3 /*
4  * Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
5  *
6  * This file is part of the device-mapper userspace tools.
7  *
8  * This copyrighted material is made available to anyone wishing to use,
9  * modify, copy, or redistribute it subject to the terms and conditions
10  * of the GNU Lesser General Public License v.2.1.
11  *
12  * You should have received a copy of the GNU Lesser General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15  */
16 
17 #include "dmlib.h"
18 #include "libdm-targets.h"
19 #include "libdm-common.h"
20 #include "libdm-netbsd.h"
21 #include "dm-ioctl.h"
22 
23 #include <stdarg.h>
24 #include <sys/param.h>
25 #include <sys/utsname.h>
26 
27 #define MAX_TARGET_PARAMSIZE 500000
28 
29 /* FIXME Fix interface so this is used only by LVM */
30 #define UUID_PREFIX "LVM-"
31 
32 /* Supported segment types */
33 enum {
34           SEG_CRYPT,
35           SEG_ERROR,
36           SEG_LINEAR,
37           SEG_MIRRORED,
38           SEG_SNAPSHOT,
39           SEG_SNAPSHOT_ORIGIN,
40           SEG_STRIPED,
41           SEG_ZERO,
42 };
43 
44 /* FIXME Add crypt and multipath support */
45 
46 struct {
47           unsigned type;
48           const char *target;
49 } dm_segtypes[] = {
50           { SEG_CRYPT, "crypt" },
51           { SEG_ERROR, "error" },
52           { SEG_LINEAR, "linear" },
53           { SEG_MIRRORED, "mirror" },
54           { SEG_SNAPSHOT, "snapshot" },
55           { SEG_SNAPSHOT_ORIGIN, "snapshot-origin" },
56           { SEG_STRIPED, "striped" },
57           { SEG_ZERO, "zero"},
58 };
59 
60 /* Some segment types have a list of areas of other devices attached */
61 struct seg_area {
62           struct dm_list list;
63 
64           struct dm_tree_node *dev_node;
65 
66           uint64_t offset;
67 };
68 
69 /* Per-segment properties */
70 struct load_segment {
71           struct dm_list list;
72 
73           unsigned type;
74 
75           uint64_t size;
76 
77           unsigned area_count;                    /* Linear + Striped + Mirrored + Crypt */
78           struct dm_list areas;                   /* Linear + Striped + Mirrored + Crypt */
79 
80           uint32_t stripe_size;                   /* Striped */
81 
82           int persistent;                         /* Snapshot */
83           uint32_t chunk_size;                    /* Snapshot */
84           struct dm_tree_node *cow;     /* Snapshot */
85           struct dm_tree_node *origin;  /* Snapshot + Snapshot origin */
86 
87           struct dm_tree_node *log;     /* Mirror */
88           uint32_t region_size;                   /* Mirror */
89           unsigned clustered;           /* Mirror */
90           unsigned mirror_area_count;   /* Mirror */
91           uint32_t flags;                         /* Mirror log */
92           char *uuid;                             /* Clustered mirror log */
93 
94           const char *cipher;           /* Crypt */
95           const char *chainmode;                  /* Crypt */
96           const char *iv;                         /* Crypt */
97           uint64_t iv_offset;           /* Crypt */
98           const char *key;              /* Crypt */
99 };
100 
101 /* Per-device properties */
102 struct load_properties {
103           int read_only;
104           uint32_t major;
105           uint32_t minor;
106 
107           uint32_t read_ahead;
108           uint32_t read_ahead_flags;
109 
110           unsigned segment_count;
111           unsigned size_changed;
112           struct dm_list segs;
113 
114           const char *new_name;
115 };
116 
117 /* Two of these used to join two nodes with uses and used_by. */
118 struct dm_tree_link {
119           struct dm_list list;
120           struct dm_tree_node *node;
121 };
122 
123 struct dm_tree_node {
124           struct dm_tree *dtree;
125 
126         const char *name;
127         const char *uuid;
128         struct dm_info info;
129 
130         struct dm_list uses;            /* Nodes this node uses */
131         struct dm_list used_by;         /* Nodes that use this node */
132 
133           int activation_priority;      /* 0 gets activated first */
134 
135           uint16_t udev_flags;                    /* Udev control flags */
136 
137           void *context;                          /* External supplied context */
138 
139           struct load_properties props; /* For creation/table (re)load */
140 };
141 
142 struct dm_tree {
143           struct dm_pool *mem;
144           struct dm_hash_table *devs;
145           struct dm_hash_table *uuids;
146           struct dm_tree_node root;
147           int skip_lockfs;              /* 1 skips lockfs (for non-snapshots) */
148           int no_flush;                 /* 1 sets noflush (mirrors/multipath) */
149           uint32_t cookie;
150 };
151 
dm_tree_create(void)152 struct dm_tree *dm_tree_create(void)
153 {
154           struct dm_tree *dtree;
155 
156           if (!(dtree = dm_malloc(sizeof(*dtree)))) {
157                     log_error("dm_tree_create malloc failed");
158                     return NULL;
159           }
160 
161           memset(dtree, 0, sizeof(*dtree));
162           dtree->root.dtree = dtree;
163           dm_list_init(&dtree->root.uses);
164           dm_list_init(&dtree->root.used_by);
165           dtree->skip_lockfs = 0;
166           dtree->no_flush = 0;
167 
168           if (!(dtree->mem = dm_pool_create("dtree", 1024))) {
169                     log_error("dtree pool creation failed");
170                     dm_free(dtree);
171                     return NULL;
172           }
173 
174           if (!(dtree->devs = dm_hash_create(8))) {
175                     log_error("dtree hash creation failed");
176                     dm_pool_destroy(dtree->mem);
177                     dm_free(dtree);
178                     return NULL;
179           }
180 
181           if (!(dtree->uuids = dm_hash_create(32))) {
182                     log_error("dtree uuid hash creation failed");
183                     dm_hash_destroy(dtree->devs);
184                     dm_pool_destroy(dtree->mem);
185                     dm_free(dtree);
186                     return NULL;
187           }
188 
189           return dtree;
190 }
191 
dm_tree_free(struct dm_tree * dtree)192 void dm_tree_free(struct dm_tree *dtree)
193 {
194           if (!dtree)
195                     return;
196 
197           dm_hash_destroy(dtree->uuids);
198           dm_hash_destroy(dtree->devs);
199           dm_pool_destroy(dtree->mem);
200           dm_free(dtree);
201 }
202 
_nodes_are_linked(struct dm_tree_node * parent,struct dm_tree_node * child)203 static int _nodes_are_linked(struct dm_tree_node *parent,
204                                    struct dm_tree_node *child)
205 {
206           struct dm_tree_link *dlink;
207 
208           dm_list_iterate_items(dlink, &parent->uses)
209                     if (dlink->node == child)
210                               return 1;
211 
212           return 0;
213 }
214 
_link(struct dm_list * list,struct dm_tree_node * node)215 static int _link(struct dm_list *list, struct dm_tree_node *node)
216 {
217           struct dm_tree_link *dlink;
218 
219           if (!(dlink = dm_pool_alloc(node->dtree->mem, sizeof(*dlink)))) {
220                     log_error("dtree link allocation failed");
221                     return 0;
222           }
223 
224           dlink->node = node;
225           dm_list_add(list, &dlink->list);
226 
227           return 1;
228 }
229 
_link_nodes(struct dm_tree_node * parent,struct dm_tree_node * child)230 static int _link_nodes(struct dm_tree_node *parent,
231                            struct dm_tree_node *child)
232 {
233           if (_nodes_are_linked(parent, child))
234                     return 1;
235 
236           if (!_link(&parent->uses, child))
237                     return 0;
238 
239           if (!_link(&child->used_by, parent))
240                     return 0;
241 
242           return 1;
243 }
244 
_unlink(struct dm_list * list,struct dm_tree_node * node)245 static void _unlink(struct dm_list *list, struct dm_tree_node *node)
246 {
247           struct dm_tree_link *dlink;
248 
249           dm_list_iterate_items(dlink, list)
250                     if (dlink->node == node) {
251                               dm_list_del(&dlink->list);
252                               break;
253                     }
254 }
255 
_unlink_nodes(struct dm_tree_node * parent,struct dm_tree_node * child)256 static void _unlink_nodes(struct dm_tree_node *parent,
257                                 struct dm_tree_node *child)
258 {
259           if (!_nodes_are_linked(parent, child))
260                     return;
261 
262           _unlink(&parent->uses, child);
263           _unlink(&child->used_by, parent);
264 }
265 
_add_to_toplevel(struct dm_tree_node * node)266 static int _add_to_toplevel(struct dm_tree_node *node)
267 {
268           return _link_nodes(&node->dtree->root, node);
269 }
270 
_remove_from_toplevel(struct dm_tree_node * node)271 static void _remove_from_toplevel(struct dm_tree_node *node)
272 {
273           return _unlink_nodes(&node->dtree->root, node);
274 }
275 
_add_to_bottomlevel(struct dm_tree_node * node)276 static int _add_to_bottomlevel(struct dm_tree_node *node)
277 {
278           return _link_nodes(node, &node->dtree->root);
279 }
280 
_remove_from_bottomlevel(struct dm_tree_node * node)281 static void _remove_from_bottomlevel(struct dm_tree_node *node)
282 {
283           return _unlink_nodes(node, &node->dtree->root);
284 }
285 
_link_tree_nodes(struct dm_tree_node * parent,struct dm_tree_node * child)286 static int _link_tree_nodes(struct dm_tree_node *parent, struct dm_tree_node *child)
287 {
288           /* Don't link to root node if child already has a parent */
289           if ((parent == &parent->dtree->root)) {
290                     if (dm_tree_node_num_children(child, 1))
291                               return 1;
292           } else
293                     _remove_from_toplevel(child);
294 
295           if ((child == &child->dtree->root)) {
296                     if (dm_tree_node_num_children(parent, 0))
297                               return 1;
298           } else
299                     _remove_from_bottomlevel(parent);
300 
301           return _link_nodes(parent, child);
302 }
303 
_create_dm_tree_node(struct dm_tree * dtree,const char * name,const char * uuid,struct dm_info * info,void * context,uint16_t udev_flags)304 static struct dm_tree_node *_create_dm_tree_node(struct dm_tree *dtree,
305                                                              const char *name,
306                                                              const char *uuid,
307                                                              struct dm_info *info,
308                                                              void *context,
309                                                              uint16_t udev_flags)
310 {
311           struct dm_tree_node *node;
312           uint64_t dev;
313 
314           if (!(node = dm_pool_zalloc(dtree->mem, sizeof(*node)))) {
315                     log_error("_create_dm_tree_node alloc failed");
316                     return NULL;
317           }
318 
319           node->dtree = dtree;
320 
321           node->name = name;
322           node->uuid = uuid;
323           node->info = *info;
324           node->context = context;
325           node->udev_flags = udev_flags;
326           node->activation_priority = 0;
327 
328           dm_list_init(&node->uses);
329           dm_list_init(&node->used_by);
330           dm_list_init(&node->props.segs);
331 
332           dev = MKDEV(info->major, info->minor);
333 
334           if (!dm_hash_insert_binary(dtree->devs, (const char *) &dev,
335                                         sizeof(dev), node)) {
336                     log_error("dtree node hash insertion failed");
337                     dm_pool_free(dtree->mem, node);
338                     return NULL;
339           }
340 
341           if (uuid && *uuid &&
342               !dm_hash_insert(dtree->uuids, uuid, node)) {
343                     log_error("dtree uuid hash insertion failed");
344                     dm_hash_remove_binary(dtree->devs, (const char *) &dev,
345                                               sizeof(dev));
346                     dm_pool_free(dtree->mem, node);
347                     return NULL;
348           }
349 
350           return node;
351 }
352 
_find_dm_tree_node(struct dm_tree * dtree,uint32_t major,uint32_t minor)353 static struct dm_tree_node *_find_dm_tree_node(struct dm_tree *dtree,
354                                                          uint32_t major, uint32_t minor)
355 {
356           uint64_t dev = MKDEV(major, minor);
357 
358           return dm_hash_lookup_binary(dtree->devs, (const char *) &dev,
359                                           sizeof(dev));
360 }
361 
_find_dm_tree_node_by_uuid(struct dm_tree * dtree,const char * uuid)362 static struct dm_tree_node *_find_dm_tree_node_by_uuid(struct dm_tree *dtree,
363                                                                    const char *uuid)
364 {
365           struct dm_tree_node *node;
366 
367           if ((node = dm_hash_lookup(dtree->uuids, uuid)))
368                     return node;
369 
370           if (strncmp(uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1))
371                     return NULL;
372 
373           return dm_hash_lookup(dtree->uuids, uuid + sizeof(UUID_PREFIX) - 1);
374 }
375 
_deps(struct dm_task ** dmt,struct dm_pool * mem,uint32_t major,uint32_t minor,const char ** name,const char ** uuid,struct dm_info * info,struct dm_deps ** deps)376 static int _deps(struct dm_task **dmt, struct dm_pool *mem, uint32_t major, uint32_t minor,
377                      const char **name, const char **uuid,
378                      struct dm_info *info, struct dm_deps **deps)
379 {
380           memset(info, 0, sizeof(*info));
381 
382           if (!dm_is_dm_major(major)) {
383                     *name = "";
384                     *uuid = "";
385                     *deps = NULL;
386                     info->major = major;
387                     info->minor = minor;
388                     info->exists = 0;
389                     info->live_table = 0;
390                     info->inactive_table = 0;
391                     info->read_only = 0;
392                     return 1;
393           }
394 
395           if (!(*dmt = dm_task_create(DM_DEVICE_DEPS))) {
396                     log_error("deps dm_task creation failed");
397                     return 0;
398           }
399 
400           if (!dm_task_set_major(*dmt, major)) {
401                     log_error("_deps: failed to set major for (%" PRIu32 ":%" PRIu32 ")",
402                                 major, minor);
403                     goto failed;
404           }
405 
406           if (!dm_task_set_minor(*dmt, minor)) {
407                     log_error("_deps: failed to set minor for (%" PRIu32 ":%" PRIu32 ")",
408                                 major, minor);
409                     goto failed;
410           }
411 
412           if (!dm_task_run(*dmt)) {
413                     log_error("_deps: task run failed for (%" PRIu32 ":%" PRIu32 ")",
414                                 major, minor);
415                     goto failed;
416           }
417 
418           if (!dm_task_get_info(*dmt, info)) {
419                     log_error("_deps: failed to get info for (%" PRIu32 ":%" PRIu32 ")",
420                                 major, minor);
421                     goto failed;
422           }
423 
424           if (!info->exists) {
425                     *name = "";
426                     *uuid = "";
427                     *deps = NULL;
428           } else {
429                     if (info->major != major) {
430                               log_error("Inconsistent dtree major number: %u != %u",
431                                           major, info->major);
432                               goto failed;
433                     }
434                     if (info->minor != minor) {
435                               log_error("Inconsistent dtree minor number: %u != %u",
436                                           minor, info->minor);
437                               goto failed;
438                     }
439                     if (!(*name = dm_pool_strdup(mem, dm_task_get_name(*dmt)))) {
440                               log_error("name pool_strdup failed");
441                               goto failed;
442                     }
443                     if (!(*uuid = dm_pool_strdup(mem, dm_task_get_uuid(*dmt)))) {
444                               log_error("uuid pool_strdup failed");
445                               goto failed;
446                     }
447                     *deps = dm_task_get_deps(*dmt);
448           }
449 
450           return 1;
451 
452 failed:
453           dm_task_destroy(*dmt);
454           return 0;
455 }
456 
_add_dev(struct dm_tree * dtree,struct dm_tree_node * parent,uint32_t major,uint32_t minor)457 static struct dm_tree_node *_add_dev(struct dm_tree *dtree,
458                                              struct dm_tree_node *parent,
459                                              uint32_t major, uint32_t minor)
460 {
461           struct dm_task *dmt = NULL;
462           struct dm_info info;
463           struct dm_deps *deps = NULL;
464           const char *name = NULL;
465           const char *uuid = NULL;
466           struct dm_tree_node *node = NULL;
467           uint32_t i;
468           int new = 0;
469 
470           /* Already in tree? */
471           if (!(node = _find_dm_tree_node(dtree, major, minor))) {
472                     if (!_deps(&dmt, dtree->mem, major, minor, &name, &uuid, &info, &deps))
473                               return_NULL;
474 
475                     if (!(node = _create_dm_tree_node(dtree, name, uuid, &info,
476                                                               NULL, 0)))
477                               goto_out;
478                     new = 1;
479           }
480 
481           if (!_link_tree_nodes(parent, node)) {
482                     node = NULL;
483                     goto_out;
484           }
485 
486           /* If node was already in tree, no need to recurse. */
487           if (!new)
488                     goto out;
489 
490           /* Can't recurse if not a mapped device or there are no dependencies */
491           if (!node->info.exists || !deps->count) {
492                     if (!_add_to_bottomlevel(node)) {
493                               stack;
494                               node = NULL;
495                     }
496                     goto out;
497           }
498 
499           /* Add dependencies to tree */
500           for (i = 0; i < deps->count; i++)
501                     if (!_add_dev(dtree, node, MAJOR(deps->device[i]),
502                                     MINOR(deps->device[i]))) {
503                               node = NULL;
504                               goto_out;
505                     }
506 
507 out:
508           if (dmt)
509                     dm_task_destroy(dmt);
510 
511           return node;
512 }
513 
_node_clear_table(struct dm_tree_node * dnode)514 static int _node_clear_table(struct dm_tree_node *dnode)
515 {
516           struct dm_task *dmt;
517           struct dm_info *info;
518           const char *name;
519           int r;
520 
521           if (!(info = &dnode->info)) {
522                     log_error("_node_clear_table failed: missing info");
523                     return 0;
524           }
525 
526           if (!(name = dm_tree_node_get_name(dnode))) {
527                     log_error("_node_clear_table failed: missing name");
528                     return 0;
529           }
530 
531           /* Is there a table? */
532           if (!info->exists || !info->inactive_table)
533                     return 1;
534 
535           log_verbose("Clearing inactive table %s (%" PRIu32 ":%" PRIu32 ")",
536                         name, info->major, info->minor);
537 
538           if (!(dmt = dm_task_create(DM_DEVICE_CLEAR))) {
539                     dm_task_destroy(dmt);
540                     log_error("Table clear dm_task creation failed for %s", name);
541                     return 0;
542           }
543 
544           if (!dm_task_set_major(dmt, info->major) ||
545               !dm_task_set_minor(dmt, info->minor)) {
546                     log_error("Failed to set device number for %s table clear", name);
547                     dm_task_destroy(dmt);
548                     return 0;
549           }
550 
551           r = dm_task_run(dmt);
552 
553           if (!dm_task_get_info(dmt, info)) {
554                     log_error("_node_clear_table failed: info missing after running task for %s", name);
555                     r = 0;
556           }
557 
558           dm_task_destroy(dmt);
559 
560           return r;
561 }
562 
dm_tree_add_new_dev(struct dm_tree * dtree,const char * name,const char * uuid,uint32_t major,uint32_t minor,int read_only,int clear_inactive,void * context)563 struct dm_tree_node *dm_tree_add_new_dev(struct dm_tree *dtree,
564                                                       const char *name,
565                                                       const char *uuid,
566                                                       uint32_t major, uint32_t minor,
567                                                       int read_only,
568                                                       int clear_inactive,
569                                                       void *context)
570 {
571           struct dm_tree_node *dnode;
572           struct dm_info info;
573           const char *name2;
574           const char *uuid2;
575 
576           /* Do we need to add node to tree? */
577           if (!(dnode = dm_tree_find_node_by_uuid(dtree, uuid))) {
578                     if (!(name2 = dm_pool_strdup(dtree->mem, name))) {
579                               log_error("name pool_strdup failed");
580                               return NULL;
581                     }
582                     if (!(uuid2 = dm_pool_strdup(dtree->mem, uuid))) {
583                               log_error("uuid pool_strdup failed");
584                               return NULL;
585                     }
586 
587                     info.major = 0;
588                     info.minor = 0;
589                     info.exists = 0;
590                     info.live_table = 0;
591                     info.inactive_table = 0;
592                     info.read_only = 0;
593 
594                     if (!(dnode = _create_dm_tree_node(dtree, name2, uuid2, &info,
595                                                                context, 0)))
596                               return_NULL;
597 
598                     /* Attach to root node until a table is supplied */
599                     if (!_add_to_toplevel(dnode) || !_add_to_bottomlevel(dnode))
600                               return_NULL;
601 
602                     dnode->props.major = major;
603                     dnode->props.minor = minor;
604                     dnode->props.new_name = NULL;
605                     dnode->props.size_changed = 0;
606           } else if (strcmp(name, dnode->name)) {
607                     /* Do we need to rename node? */
608                     if (!(dnode->props.new_name = dm_pool_strdup(dtree->mem, name))) {
609                               log_error("name pool_strdup failed");
610                               return 0;
611                     }
612           }
613 
614           dnode->props.read_only = read_only ? 1 : 0;
615           dnode->props.read_ahead = DM_READ_AHEAD_AUTO;
616           dnode->props.read_ahead_flags = 0;
617 
618           if (clear_inactive && !_node_clear_table(dnode))
619                     return_NULL;
620 
621           dnode->context = context;
622           dnode->udev_flags = 0;
623 
624           return dnode;
625 }
626 
dm_tree_add_new_dev_with_udev_flags(struct dm_tree * dtree,const char * name,const char * uuid,uint32_t major,uint32_t minor,int read_only,int clear_inactive,void * context,uint16_t udev_flags)627 struct dm_tree_node *dm_tree_add_new_dev_with_udev_flags(struct dm_tree *dtree,
628                                                                        const char *name,
629                                                                        const char *uuid,
630                                                                        uint32_t major,
631                                                                        uint32_t minor,
632                                                                        int read_only,
633                                                                        int clear_inactive,
634                                                                        void *context,
635                                                                        uint16_t udev_flags)
636 {
637           struct dm_tree_node *node;
638 
639           if ((node = dm_tree_add_new_dev(dtree, name, uuid, major, minor, read_only,
640                                                clear_inactive, context)))
641                     node->udev_flags = udev_flags;
642 
643           return node;
644 }
645 
646 
dm_tree_node_set_read_ahead(struct dm_tree_node * dnode,uint32_t read_ahead,uint32_t read_ahead_flags)647 void dm_tree_node_set_read_ahead(struct dm_tree_node *dnode,
648                                          uint32_t read_ahead,
649                                          uint32_t read_ahead_flags)
650 {
651           dnode->props.read_ahead = read_ahead;
652           dnode->props.read_ahead_flags = read_ahead_flags;
653 }
654 
dm_tree_add_dev(struct dm_tree * dtree,uint32_t major,uint32_t minor)655 int dm_tree_add_dev(struct dm_tree *dtree, uint32_t major, uint32_t minor)
656 {
657           return _add_dev(dtree, &dtree->root, major, minor) ? 1 : 0;
658 }
659 
dm_tree_node_get_name(struct dm_tree_node * node)660 const char *dm_tree_node_get_name(struct dm_tree_node *node)
661 {
662           return node->info.exists ? node->name : "";
663 }
664 
dm_tree_node_get_uuid(struct dm_tree_node * node)665 const char *dm_tree_node_get_uuid(struct dm_tree_node *node)
666 {
667           return node->info.exists ? node->uuid : "";
668 }
669 
dm_tree_node_get_info(struct dm_tree_node * node)670 const struct dm_info *dm_tree_node_get_info(struct dm_tree_node *node)
671 {
672           return &node->info;
673 }
674 
dm_tree_node_get_context(struct dm_tree_node * node)675 void *dm_tree_node_get_context(struct dm_tree_node *node)
676 {
677           return node->context;
678 }
679 
dm_tree_node_size_changed(struct dm_tree_node * dnode)680 int dm_tree_node_size_changed(struct dm_tree_node *dnode)
681 {
682           return dnode->props.size_changed;
683 }
684 
dm_tree_node_num_children(struct dm_tree_node * node,uint32_t inverted)685 int dm_tree_node_num_children(struct dm_tree_node *node, uint32_t inverted)
686 {
687           if (inverted) {
688                     if (_nodes_are_linked(&node->dtree->root, node))
689                               return 0;
690                     return dm_list_size(&node->used_by);
691           }
692 
693           if (_nodes_are_linked(node, &node->dtree->root))
694                     return 0;
695 
696           return dm_list_size(&node->uses);
697 }
698 
699 /*
700  * Returns 1 if no prefix supplied
701  */
_uuid_prefix_matches(const char * uuid,const char * uuid_prefix,size_t uuid_prefix_len)702 static int _uuid_prefix_matches(const char *uuid, const char *uuid_prefix, size_t uuid_prefix_len)
703 {
704           if (!uuid_prefix)
705                     return 1;
706 
707           if (!strncmp(uuid, uuid_prefix, uuid_prefix_len))
708                     return 1;
709 
710           /* Handle transition: active device uuids might be missing the prefix */
711           if (uuid_prefix_len <= 4)
712                     return 0;
713 
714           if (!strncmp(uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1))
715                     return 0;
716 
717           if (strncmp(uuid_prefix, UUID_PREFIX, sizeof(UUID_PREFIX) - 1))
718                     return 0;
719 
720           if (!strncmp(uuid, uuid_prefix + sizeof(UUID_PREFIX) - 1, uuid_prefix_len - (sizeof(UUID_PREFIX) - 1)))
721                     return 1;
722 
723           return 0;
724 }
725 
726 /*
727  * Returns 1 if no children.
728  */
_children_suspended(struct dm_tree_node * node,uint32_t inverted,const char * uuid_prefix,size_t uuid_prefix_len)729 static int _children_suspended(struct dm_tree_node *node,
730                                      uint32_t inverted,
731                                      const char *uuid_prefix,
732                                      size_t uuid_prefix_len)
733 {
734           struct dm_list *list;
735           struct dm_tree_link *dlink;
736           const struct dm_info *dinfo;
737           const char *uuid;
738 
739           if (inverted) {
740                     if (_nodes_are_linked(&node->dtree->root, node))
741                               return 1;
742                     list = &node->used_by;
743           } else {
744                     if (_nodes_are_linked(node, &node->dtree->root))
745                               return 1;
746                     list = &node->uses;
747           }
748 
749           dm_list_iterate_items(dlink, list) {
750                     if (!(uuid = dm_tree_node_get_uuid(dlink->node))) {
751                               stack;
752                               continue;
753                     }
754 
755                     /* Ignore if it doesn't belong to this VG */
756                     if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
757                               continue;
758 
759                     if (!(dinfo = dm_tree_node_get_info(dlink->node))) {
760                               stack;    /* FIXME Is this normal? */
761                               return 0;
762                     }
763 
764                     if (!dinfo->suspended)
765                               return 0;
766           }
767 
768           return 1;
769 }
770 
771 /*
772  * Set major and minor to zero for root of tree.
773  */
dm_tree_find_node(struct dm_tree * dtree,uint32_t major,uint32_t minor)774 struct dm_tree_node *dm_tree_find_node(struct dm_tree *dtree,
775                                                     uint32_t major,
776                                                     uint32_t minor)
777 {
778           if (!major && !minor)
779                     return &dtree->root;
780 
781           return _find_dm_tree_node(dtree, major, minor);
782 }
783 
784 /*
785  * Set uuid to NULL for root of tree.
786  */
dm_tree_find_node_by_uuid(struct dm_tree * dtree,const char * uuid)787 struct dm_tree_node *dm_tree_find_node_by_uuid(struct dm_tree *dtree,
788                                                               const char *uuid)
789 {
790           if (!uuid || !*uuid)
791                     return &dtree->root;
792 
793           return _find_dm_tree_node_by_uuid(dtree, uuid);
794 }
795 
796 /*
797  * First time set *handle to NULL.
798  * Set inverted to invert the tree.
799  */
dm_tree_next_child(void ** handle,struct dm_tree_node * parent,uint32_t inverted)800 struct dm_tree_node *dm_tree_next_child(void **handle,
801                                                      struct dm_tree_node *parent,
802                                                      uint32_t inverted)
803 {
804           struct dm_list **dlink = (struct dm_list **) handle;
805           struct dm_list *use_list;
806 
807           if (inverted)
808                     use_list = &parent->used_by;
809           else
810                     use_list = &parent->uses;
811 
812           if (!*dlink)
813                     *dlink = dm_list_first(use_list);
814           else
815                     *dlink = dm_list_next(use_list, *dlink);
816 
817           return (*dlink) ? dm_list_item(*dlink, struct dm_tree_link)->node : NULL;
818 }
819 
820 /*
821  * Deactivate a device with its dependencies if the uuid prefix matches.
822  */
_info_by_dev(uint32_t major,uint32_t minor,int with_open_count,struct dm_info * info)823 static int _info_by_dev(uint32_t major, uint32_t minor, int with_open_count,
824                               struct dm_info *info)
825 {
826           struct dm_task *dmt;
827           int r;
828 
829           if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
830                     log_error("_info_by_dev: dm_task creation failed");
831                     return 0;
832           }
833 
834           if (!dm_task_set_major(dmt, major) || !dm_task_set_minor(dmt, minor)) {
835                     log_error("_info_by_dev: Failed to set device number");
836                     dm_task_destroy(dmt);
837                     return 0;
838           }
839 
840           if (!with_open_count && !dm_task_no_open_count(dmt))
841                     log_error("Failed to disable open_count");
842 
843           if ((r = dm_task_run(dmt)))
844                     r = dm_task_get_info(dmt, info);
845 
846           dm_task_destroy(dmt);
847 
848           return r;
849 }
850 
_deactivate_node(const char * name,uint32_t major,uint32_t minor,uint32_t * cookie,uint16_t udev_flags)851 static int _deactivate_node(const char *name, uint32_t major, uint32_t minor,
852                                   uint32_t *cookie, uint16_t udev_flags)
853 {
854           struct dm_task *dmt;
855           int r = 0;
856 
857           log_verbose("Removing %s (%" PRIu32 ":%" PRIu32 ")", name, major, minor);
858 
859           if (!(dmt = dm_task_create(DM_DEVICE_REMOVE))) {
860                     log_error("Deactivation dm_task creation failed for %s", name);
861                     return 0;
862           }
863 
864           if (!dm_task_set_major(dmt, major) || !dm_task_set_minor(dmt, minor)) {
865                     log_error("Failed to set device number for %s deactivation", name);
866                     goto out;
867           }
868 
869           if (!dm_task_no_open_count(dmt))
870                     log_error("Failed to disable open_count");
871 
872           if (!dm_task_set_cookie(dmt, cookie, udev_flags))
873                     goto out;
874 
875           r = dm_task_run(dmt);
876 
877           /* FIXME Until kernel returns actual name so dm-ioctl.c can handle it */
878           rm_dev_node(name, dmt->cookie_set);
879 
880           /* FIXME Remove node from tree or mark invalid? */
881 
882 out:
883           dm_task_destroy(dmt);
884 
885           return r;
886 }
887 
_rename_node(const char * old_name,const char * new_name,uint32_t major,uint32_t minor,uint32_t * cookie,uint16_t udev_flags)888 static int _rename_node(const char *old_name, const char *new_name, uint32_t major,
889                               uint32_t minor, uint32_t *cookie, uint16_t udev_flags)
890 {
891           struct dm_task *dmt;
892           int r = 0;
893 
894           log_verbose("Renaming %s (%" PRIu32 ":%" PRIu32 ") to %s", old_name, major, minor, new_name);
895 
896           if (!(dmt = dm_task_create(DM_DEVICE_RENAME))) {
897                     log_error("Rename dm_task creation failed for %s", old_name);
898                     return 0;
899           }
900 
901           if (!dm_task_set_name(dmt, old_name)) {
902                     log_error("Failed to set name for %s rename.", old_name);
903                     goto out;
904           }
905 
906           if (!dm_task_set_newname(dmt, new_name))
907                 goto_out;
908 
909           if (!dm_task_no_open_count(dmt))
910                     log_error("Failed to disable open_count");
911 
912           if (!dm_task_set_cookie(dmt, cookie, udev_flags))
913                     goto out;
914 
915           r = dm_task_run(dmt);
916 
917 out:
918           dm_task_destroy(dmt);
919 
920           return r;
921 }
922 
923 /* FIXME Merge with _suspend_node? */
_resume_node(const char * name,uint32_t major,uint32_t minor,uint32_t read_ahead,uint32_t read_ahead_flags,struct dm_info * newinfo,uint32_t * cookie,uint16_t udev_flags)924 static int _resume_node(const char *name, uint32_t major, uint32_t minor,
925                               uint32_t read_ahead, uint32_t read_ahead_flags,
926                               struct dm_info *newinfo, uint32_t *cookie,
927                               uint16_t udev_flags)
928 {
929           struct dm_task *dmt;
930           int r = 0;
931 
932           log_verbose("Resuming %s (%" PRIu32 ":%" PRIu32 ")", name, major, minor);
933 
934           if (!(dmt = dm_task_create(DM_DEVICE_RESUME))) {
935                     log_error("Suspend dm_task creation failed for %s", name);
936                     return 0;
937           }
938 
939           /* FIXME Kernel should fill in name on return instead */
940           if (!dm_task_set_name(dmt, name)) {
941                     log_error("Failed to set readahead device name for %s", name);
942                     goto out;
943           }
944 
945           if (!dm_task_set_major(dmt, major) || !dm_task_set_minor(dmt, minor)) {
946                     log_error("Failed to set device number for %s resumption.", name);
947                     goto out;
948           }
949 
950           if (!dm_task_no_open_count(dmt))
951                     log_error("Failed to disable open_count");
952 
953           if (!dm_task_set_read_ahead(dmt, read_ahead, read_ahead_flags))
954                     log_error("Failed to set read ahead");
955 
956           if (!dm_task_set_cookie(dmt, cookie, udev_flags))
957                     goto out;
958 
959           if ((r = dm_task_run(dmt)))
960                     r = dm_task_get_info(dmt, newinfo);
961 
962 out:
963           dm_task_destroy(dmt);
964 
965           return r;
966 }
967 
_suspend_node(const char * name,uint32_t major,uint32_t minor,int skip_lockfs,int no_flush,struct dm_info * newinfo)968 static int _suspend_node(const char *name, uint32_t major, uint32_t minor,
969                                int skip_lockfs, int no_flush, struct dm_info *newinfo)
970 {
971           struct dm_task *dmt;
972           int r;
973 
974           log_verbose("Suspending %s (%" PRIu32 ":%" PRIu32 ")%s%s",
975                         name, major, minor,
976                         skip_lockfs ? "" : " with filesystem sync",
977                         no_flush ? "" : " with device flush");
978 
979           if (!(dmt = dm_task_create(DM_DEVICE_SUSPEND))) {
980                     log_error("Suspend dm_task creation failed for %s", name);
981                     return 0;
982           }
983 
984           if (!dm_task_set_major(dmt, major) || !dm_task_set_minor(dmt, minor)) {
985                     log_error("Failed to set device number for %s suspension.", name);
986                     dm_task_destroy(dmt);
987                     return 0;
988           }
989 
990           if (!dm_task_no_open_count(dmt))
991                     log_error("Failed to disable open_count");
992 
993           if (skip_lockfs && !dm_task_skip_lockfs(dmt))
994                     log_error("Failed to set skip_lockfs flag.");
995 
996           if (no_flush && !dm_task_no_flush(dmt))
997                     log_error("Failed to set no_flush flag.");
998 
999           if ((r = dm_task_run(dmt)))
1000                     r = dm_task_get_info(dmt, newinfo);
1001 
1002           dm_task_destroy(dmt);
1003 
1004           return r;
1005 }
1006 
dm_tree_deactivate_children(struct dm_tree_node * dnode,const char * uuid_prefix,size_t uuid_prefix_len)1007 int dm_tree_deactivate_children(struct dm_tree_node *dnode,
1008                                            const char *uuid_prefix,
1009                                            size_t uuid_prefix_len)
1010 {
1011           void *handle = NULL;
1012           struct dm_tree_node *child = dnode;
1013           struct dm_info info;
1014           const struct dm_info *dinfo;
1015           const char *name;
1016           const char *uuid;
1017 
1018           while ((child = dm_tree_next_child(&handle, dnode, 0))) {
1019                     if (!(dinfo = dm_tree_node_get_info(child))) {
1020                               stack;
1021                               continue;
1022                     }
1023 
1024                     if (!(name = dm_tree_node_get_name(child))) {
1025                               stack;
1026                               continue;
1027                     }
1028 
1029                     if (!(uuid = dm_tree_node_get_uuid(child))) {
1030                               stack;
1031                               continue;
1032                     }
1033 
1034                     /* Ignore if it doesn't belong to this VG */
1035                     if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
1036                               continue;
1037 
1038                     /* Refresh open_count */
1039                     if (!_info_by_dev(dinfo->major, dinfo->minor, 1, &info) ||
1040                         !info.exists || info.open_count)
1041                               continue;
1042 
1043                     if (!_deactivate_node(name, info.major, info.minor,
1044                                               &child->dtree->cookie, child->udev_flags)) {
1045                               log_error("Unable to deactivate %s (%" PRIu32
1046                                           ":%" PRIu32 ")", name, info.major,
1047                                           info.minor);
1048                               continue;
1049                     }
1050 
1051                     if (dm_tree_node_num_children(child, 0))
1052                               dm_tree_deactivate_children(child, uuid_prefix, uuid_prefix_len);
1053           }
1054 
1055           return 1;
1056 }
1057 
dm_tree_skip_lockfs(struct dm_tree_node * dnode)1058 void dm_tree_skip_lockfs(struct dm_tree_node *dnode)
1059 {
1060           dnode->dtree->skip_lockfs = 1;
1061 }
1062 
dm_tree_use_no_flush_suspend(struct dm_tree_node * dnode)1063 void dm_tree_use_no_flush_suspend(struct dm_tree_node *dnode)
1064 {
1065           dnode->dtree->no_flush = 1;
1066 }
1067 
dm_tree_suspend_children(struct dm_tree_node * dnode,const char * uuid_prefix,size_t uuid_prefix_len)1068 int dm_tree_suspend_children(struct dm_tree_node *dnode,
1069                                            const char *uuid_prefix,
1070                                            size_t uuid_prefix_len)
1071 {
1072           void *handle = NULL;
1073           struct dm_tree_node *child = dnode;
1074           struct dm_info info, newinfo;
1075           const struct dm_info *dinfo;
1076           const char *name;
1077           const char *uuid;
1078 
1079           /* Suspend nodes at this level of the tree */
1080           while ((child = dm_tree_next_child(&handle, dnode, 0))) {
1081                     if (!(dinfo = dm_tree_node_get_info(child))) {
1082                               stack;
1083                               continue;
1084                     }
1085 
1086                     if (!(name = dm_tree_node_get_name(child))) {
1087                               stack;
1088                               continue;
1089                     }
1090 
1091                     if (!(uuid = dm_tree_node_get_uuid(child))) {
1092                               stack;
1093                               continue;
1094                     }
1095 
1096                     /* Ignore if it doesn't belong to this VG */
1097                     if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
1098                               continue;
1099 
1100                     /* Ensure immediate parents are already suspended */
1101                     if (!_children_suspended(child, 1, uuid_prefix, uuid_prefix_len))
1102                               continue;
1103 
1104                     if (!_info_by_dev(dinfo->major, dinfo->minor, 0, &info) ||
1105                         !info.exists || info.suspended)
1106                               continue;
1107 
1108                     if (!_suspend_node(name, info.major, info.minor,
1109                                            child->dtree->skip_lockfs,
1110                                            child->dtree->no_flush, &newinfo)) {
1111                               log_error("Unable to suspend %s (%" PRIu32
1112                                           ":%" PRIu32 ")", name, info.major,
1113                                           info.minor);
1114                               continue;
1115                     }
1116 
1117                     /* Update cached info */
1118                     child->info = newinfo;
1119           }
1120 
1121           /* Then suspend any child nodes */
1122           handle = NULL;
1123 
1124           while ((child = dm_tree_next_child(&handle, dnode, 0))) {
1125                     if (!(uuid = dm_tree_node_get_uuid(child))) {
1126                               stack;
1127                               continue;
1128                     }
1129 
1130                     /* Ignore if it doesn't belong to this VG */
1131                     if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
1132                               continue;
1133 
1134                     if (dm_tree_node_num_children(child, 0))
1135                               dm_tree_suspend_children(child, uuid_prefix, uuid_prefix_len);
1136           }
1137 
1138           return 1;
1139 }
1140 
dm_tree_activate_children(struct dm_tree_node * dnode,const char * uuid_prefix,size_t uuid_prefix_len)1141 int dm_tree_activate_children(struct dm_tree_node *dnode,
1142                                          const char *uuid_prefix,
1143                                          size_t uuid_prefix_len)
1144 {
1145           void *handle = NULL;
1146           struct dm_tree_node *child = dnode;
1147           struct dm_info newinfo;
1148           const char *name;
1149           const char *uuid;
1150           int priority;
1151 
1152           /* Activate children first */
1153           while ((child = dm_tree_next_child(&handle, dnode, 0))) {
1154                     if (!(uuid = dm_tree_node_get_uuid(child))) {
1155                               stack;
1156                               continue;
1157                     }
1158 
1159                     if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
1160                               continue;
1161 
1162                     if (dm_tree_node_num_children(child, 0))
1163                               dm_tree_activate_children(child, uuid_prefix, uuid_prefix_len);
1164           }
1165 
1166           handle = NULL;
1167 
1168           for (priority = 0; priority < 2; priority++) {
1169                     while ((child = dm_tree_next_child(&handle, dnode, 0))) {
1170                               if (!(uuid = dm_tree_node_get_uuid(child))) {
1171                                         stack;
1172                                         continue;
1173                               }
1174 
1175                               if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
1176                                         continue;
1177 
1178                               if (priority != child->activation_priority)
1179                                         continue;
1180 
1181                               if (!(name = dm_tree_node_get_name(child))) {
1182                                         stack;
1183                                         continue;
1184                               }
1185 
1186                               /* Rename? */
1187                               if (child->props.new_name) {
1188                                         if (!_rename_node(name, child->props.new_name, child->info.major,
1189                                                               child->info.minor, &child->dtree->cookie,
1190                                                               child->udev_flags)) {
1191                                                   log_error("Failed to rename %s (%" PRIu32
1192                                                               ":%" PRIu32 ") to %s", name, child->info.major,
1193                                                               child->info.minor, child->props.new_name);
1194                                                   return 0;
1195                                         }
1196                                         child->name = child->props.new_name;
1197                                         child->props.new_name = NULL;
1198                               }
1199 
1200                               if (!child->info.inactive_table && !child->info.suspended)
1201                                         continue;
1202 
1203                               if (!_resume_node(child->name, child->info.major, child->info.minor,
1204                                                     child->props.read_ahead, child->props.read_ahead_flags,
1205                                                     &newinfo, &child->dtree->cookie, child->udev_flags)) {
1206                                         log_error("Unable to resume %s (%" PRIu32
1207                                                     ":%" PRIu32 ")", child->name, child->info.major,
1208                                                     child->info.minor);
1209                                         continue;
1210                               }
1211 
1212                               /* Update cached info */
1213                               child->info = newinfo;
1214                     }
1215           }
1216 
1217           handle = NULL;
1218 
1219           return 1;
1220 }
1221 
_create_node(struct dm_tree_node * dnode)1222 static int _create_node(struct dm_tree_node *dnode)
1223 {
1224           int r = 0;
1225           struct dm_task *dmt;
1226 
1227           log_verbose("Creating %s", dnode->name);
1228 
1229           if (!(dmt = dm_task_create(DM_DEVICE_CREATE))) {
1230                     log_error("Create dm_task creation failed for %s", dnode->name);
1231                     return 0;
1232           }
1233 
1234           if (!dm_task_set_name(dmt, dnode->name)) {
1235                     log_error("Failed to set device name for %s", dnode->name);
1236                     goto out;
1237           }
1238 
1239           if (!dm_task_set_uuid(dmt, dnode->uuid)) {
1240                     log_error("Failed to set uuid for %s", dnode->name);
1241                     goto out;
1242           }
1243 
1244           if (dnode->props.major &&
1245               (!dm_task_set_major(dmt, dnode->props.major) ||
1246                !dm_task_set_minor(dmt, dnode->props.minor))) {
1247                     log_error("Failed to set device number for %s creation.", dnode->name);
1248                     goto out;
1249           }
1250 
1251           if (dnode->props.read_only && !dm_task_set_ro(dmt)) {
1252                     log_error("Failed to set read only flag for %s", dnode->name);
1253                     goto out;
1254           }
1255 
1256           if (!dm_task_no_open_count(dmt))
1257                     log_error("Failed to disable open_count");
1258 
1259           if ((r = dm_task_run(dmt)))
1260                     r = dm_task_get_info(dmt, &dnode->info);
1261 
1262 out:
1263           dm_task_destroy(dmt);
1264 
1265           return r;
1266 }
1267 
1268 
_build_dev_string(char * devbuf,size_t bufsize,struct dm_tree_node * node)1269 static int _build_dev_string(char *devbuf, size_t bufsize, struct dm_tree_node *node)
1270 {
1271           if (!dm_format_dev(devbuf, bufsize, node->info.major, node->info.minor)) {
1272                 log_error("Failed to format %s device number for %s as dm "
1273                           "target (%u,%u)",
1274                           node->name, node->uuid, node->info.major, node->info.minor);
1275                 return 0;
1276           }
1277 
1278           return 1;
1279 }
1280 
1281 /* simplify string emiting code */
1282 #define EMIT_PARAMS(p, str...)\
1283 do {\
1284           int w;\
1285           if ((w = dm_snprintf(params + p, paramsize - (size_t) p, str)) < 0) {\
1286                     stack; /* Out of space */\
1287                     return -1;\
1288           }\
1289           p += w;\
1290 } while (0)
1291 
1292 /*
1293  * _emit_areas_line
1294  *
1295  * Returns: 1 on success, 0 on failure
1296  */
_emit_areas_line(struct dm_task * dmt __attribute ((unused)),struct load_segment * seg,char * params,size_t paramsize,int * pos)1297 static int _emit_areas_line(struct dm_task *dmt __attribute((unused)),
1298                                   struct load_segment *seg, char *params,
1299                                   size_t paramsize, int *pos)
1300 {
1301           struct seg_area *area;
1302           char devbuf[DM_FORMAT_DEV_BUFSIZE];
1303           unsigned first_time = 1;
1304 
1305           dm_list_iterate_items(area, &seg->areas) {
1306                     if (!_build_dev_string(devbuf, sizeof(devbuf), area->dev_node))
1307                               return_0;
1308 
1309                     EMIT_PARAMS(*pos, "%s%s %" PRIu64, first_time ? "" : " ",
1310                                   devbuf, area->offset);
1311 
1312                     first_time = 0;
1313           }
1314 
1315           return 1;
1316 }
1317 
1318 /*
1319  * Returns: 1 on success, 0 on failure
1320  */
_mirror_emit_segment_line(struct dm_task * dmt,uint32_t major,uint32_t minor,struct load_segment * seg,uint64_t * seg_start,char * params,size_t paramsize)1321 static int _mirror_emit_segment_line(struct dm_task *dmt, uint32_t major,
1322                                              uint32_t minor, struct load_segment *seg,
1323                                              uint64_t *seg_start, char *params,
1324                                              size_t paramsize)
1325 {
1326           int r;
1327           int block_on_error = 0;
1328           int handle_errors = 0;
1329           int dm_log_userspace = 0;
1330           struct utsname uts;
1331           unsigned log_parm_count;
1332           int pos = 0;
1333           char logbuf[DM_FORMAT_DEV_BUFSIZE];
1334           const char *logtype;
1335 
1336           r = uname(&uts);
1337           if (r)
1338                     return_0;
1339 
1340           if ((seg->flags & DM_BLOCK_ON_ERROR)) {
1341                     /*
1342                      * Originally, block_on_error was an argument to the log
1343                      * portion of the mirror CTR table.  It was renamed to
1344                      * "handle_errors" and now resides in the 'features'
1345                      * section of the mirror CTR table (i.e. at the end).
1346                      *
1347                      * We can identify whether to use "block_on_error" or
1348                      * "handle_errors" by the dm-mirror module's version
1349                      * number (>= 1.12) or by the kernel version (>= 2.6.22).
1350                      */
1351                     if (strncmp(uts.release, "2.6.22", 6) >= 0)
1352                               handle_errors = 1;
1353                     else
1354                               block_on_error = 1;
1355           }
1356 
1357           if (seg->clustered) {
1358                     /* Cluster mirrors require a UUID */
1359                     if (!seg->uuid)
1360                               return_0;
1361 
1362                     /*
1363                      * Cluster mirrors used to have their own log
1364                      * types.  Now they are accessed through the
1365                      * userspace log type.
1366                      *
1367                      * The dm-log-userspace module was added to the
1368                      * 2.6.31 kernel.
1369                      */
1370                     if (strncmp(uts.release, "2.6.31", 6) >= 0)
1371                               dm_log_userspace = 1;
1372           }
1373 
1374           /* Region size */
1375           log_parm_count = 1;
1376 
1377           /* [no]sync, block_on_error etc. */
1378           log_parm_count += hweight32(seg->flags);
1379 
1380           /* "handle_errors" is a feature arg now */
1381           if (handle_errors)
1382                     log_parm_count--;
1383 
1384           /* DM_CORELOG does not count in the param list */
1385           if (seg->flags & DM_CORELOG)
1386                     log_parm_count--;
1387 
1388           if (seg->clustered) {
1389                     log_parm_count++; /* For UUID */
1390 
1391                     if (!dm_log_userspace)
1392                               EMIT_PARAMS(pos, "clustered-");
1393           }
1394 
1395           if (!seg->log)
1396                     logtype = "core";
1397           else {
1398                     logtype = "disk";
1399                     log_parm_count++;
1400                     if (!_build_dev_string(logbuf, sizeof(logbuf), seg->log))
1401                               return_0;
1402           }
1403 
1404           if (dm_log_userspace)
1405                     EMIT_PARAMS(pos, "userspace %u %s clustered-%s",
1406                                   log_parm_count, seg->uuid, logtype);
1407           else
1408                     EMIT_PARAMS(pos, "%s %u", logtype, log_parm_count);
1409 
1410           if (seg->log)
1411                     EMIT_PARAMS(pos, " %s", logbuf);
1412 
1413           EMIT_PARAMS(pos, " %u", seg->region_size);
1414 
1415           if (seg->clustered && !dm_log_userspace)
1416                     EMIT_PARAMS(pos, " %s", seg->uuid);
1417 
1418           if ((seg->flags & DM_NOSYNC))
1419                     EMIT_PARAMS(pos, " nosync");
1420           else if ((seg->flags & DM_FORCESYNC))
1421                     EMIT_PARAMS(pos, " sync");
1422 
1423           if (block_on_error)
1424                     EMIT_PARAMS(pos, " block_on_error");
1425 
1426           EMIT_PARAMS(pos, " %u ", seg->mirror_area_count);
1427 
1428           if ((r = _emit_areas_line(dmt, seg, params, paramsize, &pos)) <= 0)
1429                     return_0;
1430 
1431           if (handle_errors)
1432                     EMIT_PARAMS(pos, " 1 handle_errors");
1433 
1434           return 1;
1435 }
1436 
_emit_segment_line(struct dm_task * dmt,uint32_t major,uint32_t minor,struct load_segment * seg,uint64_t * seg_start,char * params,size_t paramsize)1437 static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
1438                                     uint32_t minor, struct load_segment *seg,
1439                                     uint64_t *seg_start, char *params,
1440                                     size_t paramsize)
1441 {
1442           int pos = 0;
1443           int r;
1444           char originbuf[DM_FORMAT_DEV_BUFSIZE], cowbuf[DM_FORMAT_DEV_BUFSIZE];
1445 
1446           switch(seg->type) {
1447           case SEG_ERROR:
1448           case SEG_ZERO:
1449           case SEG_LINEAR:
1450                     break;
1451           case SEG_MIRRORED:
1452                     /* Mirrors are pretty complicated - now in separate function */
1453                     r = _mirror_emit_segment_line(dmt, major, minor, seg, seg_start,
1454                                                         params, paramsize);
1455                     if (!r)
1456                               return_0;
1457                     break;
1458           case SEG_SNAPSHOT:
1459                     if (!_build_dev_string(originbuf, sizeof(originbuf), seg->origin))
1460                               return_0;
1461                     if (!_build_dev_string(cowbuf, sizeof(cowbuf), seg->cow))
1462                               return_0;
1463                     EMIT_PARAMS(pos, "%s %s %c %d", originbuf, cowbuf,
1464                                   seg->persistent ? 'P' : 'N', seg->chunk_size);
1465                     break;
1466           case SEG_SNAPSHOT_ORIGIN:
1467                     if (!_build_dev_string(originbuf, sizeof(originbuf), seg->origin))
1468                               return_0;
1469                     EMIT_PARAMS(pos, "%s", originbuf);
1470                     break;
1471           case SEG_STRIPED:
1472                     EMIT_PARAMS(pos, "%u %u ", seg->area_count, seg->stripe_size);
1473                     break;
1474           case SEG_CRYPT:
1475                     EMIT_PARAMS(pos, "%s%s%s%s%s %s %" PRIu64 " ", seg->cipher,
1476                                   seg->chainmode ? "-" : "", seg->chainmode ?: "",
1477                                   seg->iv ? "-" : "", seg->iv ?: "", seg->key,
1478                                   seg->iv_offset != DM_CRYPT_IV_DEFAULT ?
1479                                   seg->iv_offset : *seg_start);
1480                     break;
1481           }
1482 
1483           switch(seg->type) {
1484           case SEG_ERROR:
1485           case SEG_SNAPSHOT:
1486           case SEG_SNAPSHOT_ORIGIN:
1487           case SEG_ZERO:
1488                     break;
1489           case SEG_CRYPT:
1490           case SEG_LINEAR:
1491           case SEG_STRIPED:
1492                     if ((r = _emit_areas_line(dmt, seg, params, paramsize, &pos)) <= 0) {
1493                               stack;
1494                               return r;
1495                     }
1496                     break;
1497           }
1498 
1499           log_debug("Adding target to (%" PRIu32 ":%" PRIu32 "): %" PRIu64
1500                       " %" PRIu64 " %s %s", major, minor,
1501                       *seg_start, seg->size, dm_segtypes[seg->type].target, params);
1502 
1503           if (!dm_task_add_target(dmt, *seg_start, seg->size, dm_segtypes[seg->type].target, params))
1504                     return_0;
1505 
1506           *seg_start += seg->size;
1507 
1508           return 1;
1509 }
1510 
1511 #undef EMIT_PARAMS
1512 
_emit_segment(struct dm_task * dmt,uint32_t major,uint32_t minor,struct load_segment * seg,uint64_t * seg_start)1513 static int _emit_segment(struct dm_task *dmt, uint32_t major, uint32_t minor,
1514                                struct load_segment *seg, uint64_t *seg_start)
1515 {
1516           char *params;
1517           size_t paramsize = 4096;
1518           int ret;
1519 
1520           do {
1521                     if (!(params = dm_malloc(paramsize))) {
1522                               log_error("Insufficient space for target parameters.");
1523                               return 0;
1524                     }
1525 
1526                     params[0] = '\0';
1527                     ret = _emit_segment_line(dmt, major, minor, seg, seg_start,
1528                                                    params, paramsize);
1529                     dm_free(params);
1530 
1531                     if (!ret)
1532                               stack;
1533 
1534                     if (ret >= 0)
1535                               return ret;
1536 
1537                     log_debug("Insufficient space in params[%" PRIsize_t
1538                                 "] for target parameters.", paramsize);
1539 
1540                     paramsize *= 2;
1541           } while (paramsize < MAX_TARGET_PARAMSIZE);
1542 
1543           log_error("Target parameter size too big. Aborting.");
1544           return 0;
1545 }
1546 
_load_node(struct dm_tree_node * dnode)1547 static int _load_node(struct dm_tree_node *dnode)
1548 {
1549           int r = 0;
1550           struct dm_task *dmt;
1551           struct load_segment *seg;
1552           uint64_t seg_start = 0;
1553 
1554           log_verbose("Loading %s table (%" PRIu32 ":%" PRIu32 ")", dnode->name,
1555                         dnode->info.major, dnode->info.minor);
1556 
1557           if (!(dmt = dm_task_create(DM_DEVICE_RELOAD))) {
1558                     log_error("Reload dm_task creation failed for %s", dnode->name);
1559                     return 0;
1560           }
1561 
1562           if (!dm_task_set_major(dmt, dnode->info.major) ||
1563               !dm_task_set_minor(dmt, dnode->info.minor)) {
1564                     log_error("Failed to set device number for %s reload.", dnode->name);
1565                     goto out;
1566           }
1567 
1568           if (dnode->props.read_only && !dm_task_set_ro(dmt)) {
1569                     log_error("Failed to set read only flag for %s", dnode->name);
1570                     goto out;
1571           }
1572 
1573           if (!dm_task_no_open_count(dmt))
1574                     log_error("Failed to disable open_count");
1575 
1576           dm_list_iterate_items(seg, &dnode->props.segs)
1577                     if (!_emit_segment(dmt, dnode->info.major, dnode->info.minor,
1578                                            seg, &seg_start))
1579                               goto_out;
1580 
1581           if (!dm_task_suppress_identical_reload(dmt))
1582                     log_error("Failed to suppress reload of identical tables.");
1583 
1584           if ((r = dm_task_run(dmt))) {
1585                     r = dm_task_get_info(dmt, &dnode->info);
1586                     if (r && !dnode->info.inactive_table)
1587                               log_verbose("Suppressed %s identical table reload.",
1588                                             dnode->name);
1589 
1590                     if ((dnode->props.size_changed =
1591                          (dm_task_get_existing_table_size(dmt) == seg_start) ? 0 : 1))
1592                               log_debug("Table size changed from %" PRIu64 " to %"
1593                                           PRIu64 " for %s",
1594                                           dm_task_get_existing_table_size(dmt),
1595                                           seg_start, dnode->name);
1596           }
1597 
1598           dnode->props.segment_count = 0;
1599 
1600 out:
1601           dm_task_destroy(dmt);
1602 
1603           return r;
1604 }
1605 
dm_tree_preload_children(struct dm_tree_node * dnode,const char * uuid_prefix,size_t uuid_prefix_len)1606 int dm_tree_preload_children(struct dm_tree_node *dnode,
1607                                    const char *uuid_prefix,
1608                                    size_t uuid_prefix_len)
1609 {
1610           void *handle = NULL;
1611           struct dm_tree_node *child;
1612           struct dm_info newinfo;
1613 
1614           /* Preload children first */
1615           while ((child = dm_tree_next_child(&handle, dnode, 0))) {
1616                     /* Skip existing non-device-mapper devices */
1617                     if (!child->info.exists && child->info.major)
1618                               continue;
1619 
1620                     /* Ignore if it doesn't belong to this VG */
1621                     if (child->info.exists &&
1622                         !_uuid_prefix_matches(child->uuid, uuid_prefix, uuid_prefix_len))
1623                               continue;
1624 
1625                     if (dm_tree_node_num_children(child, 0))
1626                               dm_tree_preload_children(child, uuid_prefix, uuid_prefix_len);
1627 
1628                     /* FIXME Cope if name exists with no uuid? */
1629                     if (!child->info.exists) {
1630                               if (!_create_node(child)) {
1631                                         stack;
1632                                         return 0;
1633                               }
1634                     }
1635 
1636                     if (!child->info.inactive_table && child->props.segment_count) {
1637                               if (!_load_node(child)) {
1638                                         stack;
1639                                         return 0;
1640                               }
1641                     }
1642 
1643                     /* Propagate device size change change */
1644                     if (child->props.size_changed)
1645                               dnode->props.size_changed = 1;
1646 
1647                     /* Resume device immediately if it has parents and its size changed */
1648                     if (!dm_tree_node_num_children(child, 1) || !child->props.size_changed)
1649                               continue;
1650 
1651                     if (!child->info.inactive_table && !child->info.suspended)
1652                               continue;
1653 
1654                     if (!_resume_node(child->name, child->info.major, child->info.minor,
1655                                           child->props.read_ahead, child->props.read_ahead_flags,
1656                                           &newinfo, &child->dtree->cookie, child->udev_flags)) {
1657                               log_error("Unable to resume %s (%" PRIu32
1658                                           ":%" PRIu32 ")", child->name, child->info.major,
1659                                           child->info.minor);
1660                               continue;
1661                     }
1662 
1663                     /* Update cached info */
1664                     child->info = newinfo;
1665           }
1666 
1667           handle = NULL;
1668 
1669           return 1;
1670 }
1671 
1672 /*
1673  * Returns 1 if unsure.
1674  */
dm_tree_children_use_uuid(struct dm_tree_node * dnode,const char * uuid_prefix,size_t uuid_prefix_len)1675 int dm_tree_children_use_uuid(struct dm_tree_node *dnode,
1676                                          const char *uuid_prefix,
1677                                          size_t uuid_prefix_len)
1678 {
1679           void *handle = NULL;
1680           struct dm_tree_node *child = dnode;
1681           const char *uuid;
1682 
1683           while ((child = dm_tree_next_child(&handle, dnode, 0))) {
1684                     if (!(uuid = dm_tree_node_get_uuid(child))) {
1685                               log_error("Failed to get uuid for dtree node.");
1686                               return 1;
1687                     }
1688 
1689                     if (_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
1690                               return 1;
1691 
1692                     if (dm_tree_node_num_children(child, 0))
1693                               dm_tree_children_use_uuid(child, uuid_prefix, uuid_prefix_len);
1694           }
1695 
1696           return 0;
1697 }
1698 
1699 /*
1700  * Target functions
1701  */
_add_segment(struct dm_tree_node * dnode,unsigned type,uint64_t size)1702 static struct load_segment *_add_segment(struct dm_tree_node *dnode, unsigned type, uint64_t size)
1703 {
1704           struct load_segment *seg;
1705 
1706           if (!(seg = dm_pool_zalloc(dnode->dtree->mem, sizeof(*seg)))) {
1707                     log_error("dtree node segment allocation failed");
1708                     return NULL;
1709           }
1710 
1711           seg->type = type;
1712           seg->size = size;
1713           seg->area_count = 0;
1714           dm_list_init(&seg->areas);
1715           seg->stripe_size = 0;
1716           seg->persistent = 0;
1717           seg->chunk_size = 0;
1718           seg->cow = NULL;
1719           seg->origin = NULL;
1720 
1721           dm_list_add(&dnode->props.segs, &seg->list);
1722           dnode->props.segment_count++;
1723 
1724           return seg;
1725 }
1726 
dm_tree_node_add_snapshot_origin_target(struct dm_tree_node * dnode,uint64_t size,const char * origin_uuid)1727 int dm_tree_node_add_snapshot_origin_target(struct dm_tree_node *dnode,
1728                                                uint64_t size,
1729                                                const char *origin_uuid)
1730 {
1731           struct load_segment *seg;
1732           struct dm_tree_node *origin_node;
1733 
1734           if (!(seg = _add_segment(dnode, SEG_SNAPSHOT_ORIGIN, size)))
1735                     return_0;
1736 
1737           if (!(origin_node = dm_tree_find_node_by_uuid(dnode->dtree, origin_uuid))) {
1738                     log_error("Couldn't find snapshot origin uuid %s.", origin_uuid);
1739                     return 0;
1740           }
1741 
1742           seg->origin = origin_node;
1743           if (!_link_tree_nodes(dnode, origin_node))
1744                     return_0;
1745 
1746           /* Resume snapshot origins after new snapshots */
1747           dnode->activation_priority = 1;
1748 
1749           return 1;
1750 }
1751 
dm_tree_node_add_snapshot_target(struct dm_tree_node * node,uint64_t size,const char * origin_uuid,const char * cow_uuid,int persistent,uint32_t chunk_size)1752 int dm_tree_node_add_snapshot_target(struct dm_tree_node *node,
1753                                         uint64_t size,
1754                                         const char *origin_uuid,
1755                                         const char *cow_uuid,
1756                                         int persistent,
1757                                         uint32_t chunk_size)
1758 {
1759           struct load_segment *seg;
1760           struct dm_tree_node *origin_node, *cow_node;
1761 
1762           if (!(seg = _add_segment(node, SEG_SNAPSHOT, size)))
1763                     return_0;
1764 
1765           if (!(origin_node = dm_tree_find_node_by_uuid(node->dtree, origin_uuid))) {
1766                     log_error("Couldn't find snapshot origin uuid %s.", origin_uuid);
1767                     return 0;
1768           }
1769 
1770           seg->origin = origin_node;
1771           if (!_link_tree_nodes(node, origin_node))
1772                     return_0;
1773 
1774           if (!(cow_node = dm_tree_find_node_by_uuid(node->dtree, cow_uuid))) {
1775                     log_error("Couldn't find snapshot origin uuid %s.", cow_uuid);
1776                     return 0;
1777           }
1778 
1779           seg->cow = cow_node;
1780           if (!_link_tree_nodes(node, cow_node))
1781                     return_0;
1782 
1783           seg->persistent = persistent ? 1 : 0;
1784           seg->chunk_size = chunk_size;
1785 
1786           return 1;
1787 }
1788 
dm_tree_node_add_error_target(struct dm_tree_node * node,uint64_t size)1789 int dm_tree_node_add_error_target(struct dm_tree_node *node,
1790                                      uint64_t size)
1791 {
1792           if (!_add_segment(node, SEG_ERROR, size))
1793                     return_0;
1794 
1795           return 1;
1796 }
1797 
dm_tree_node_add_zero_target(struct dm_tree_node * node,uint64_t size)1798 int dm_tree_node_add_zero_target(struct dm_tree_node *node,
1799                                     uint64_t size)
1800 {
1801           if (!_add_segment(node, SEG_ZERO, size))
1802                     return_0;
1803 
1804           return 1;
1805 }
1806 
dm_tree_node_add_linear_target(struct dm_tree_node * node,uint64_t size)1807 int dm_tree_node_add_linear_target(struct dm_tree_node *node,
1808                                       uint64_t size)
1809 {
1810           if (!_add_segment(node, SEG_LINEAR, size))
1811                     return_0;
1812 
1813           return 1;
1814 }
1815 
dm_tree_node_add_striped_target(struct dm_tree_node * node,uint64_t size,uint32_t stripe_size)1816 int dm_tree_node_add_striped_target(struct dm_tree_node *node,
1817                                        uint64_t size,
1818                                        uint32_t stripe_size)
1819 {
1820           struct load_segment *seg;
1821 
1822           if (!(seg = _add_segment(node, SEG_STRIPED, size)))
1823                     return_0;
1824 
1825           seg->stripe_size = stripe_size;
1826 
1827           return 1;
1828 }
1829 
dm_tree_node_add_crypt_target(struct dm_tree_node * node,uint64_t size,const char * cipher,const char * chainmode,const char * iv,uint64_t iv_offset,const char * key)1830 int dm_tree_node_add_crypt_target(struct dm_tree_node *node,
1831                                           uint64_t size,
1832                                           const char *cipher,
1833                                           const char *chainmode,
1834                                           const char *iv,
1835                                           uint64_t iv_offset,
1836                                           const char *key)
1837 {
1838           struct load_segment *seg;
1839 
1840           if (!(seg = _add_segment(node, SEG_CRYPT, size)))
1841                     return_0;
1842 
1843           seg->cipher = cipher;
1844           seg->chainmode = chainmode;
1845           seg->iv = iv;
1846           seg->iv_offset = iv_offset;
1847           seg->key = key;
1848 
1849           return 1;
1850 }
1851 
dm_tree_node_add_mirror_target_log(struct dm_tree_node * node,uint32_t region_size,unsigned clustered,const char * log_uuid,unsigned area_count,uint32_t flags)1852 int dm_tree_node_add_mirror_target_log(struct dm_tree_node *node,
1853                                                     uint32_t region_size,
1854                                                     unsigned clustered,
1855                                                     const char *log_uuid,
1856                                                     unsigned area_count,
1857                                                     uint32_t flags)
1858 {
1859           struct dm_tree_node *log_node = NULL;
1860           struct load_segment *seg;
1861 
1862           if (!node->props.segment_count) {
1863                     log_error("Internal error: Attempt to add target area to missing segment.");
1864                     return 0;
1865           }
1866 
1867           seg = dm_list_item(dm_list_last(&node->props.segs), struct load_segment);
1868 
1869           if (log_uuid) {
1870                     if (!(seg->uuid = dm_pool_strdup(node->dtree->mem, log_uuid))) {
1871                               log_error("log uuid pool_strdup failed");
1872                               return 0;
1873                     }
1874                     if (!(flags & DM_CORELOG)) {
1875                               if (!(log_node = dm_tree_find_node_by_uuid(node->dtree, log_uuid))) {
1876                                         log_error("Couldn't find mirror log uuid %s.", log_uuid);
1877                                         return 0;
1878                               }
1879 
1880                               if (!_link_tree_nodes(node, log_node))
1881                                         return_0;
1882                     }
1883           }
1884 
1885           seg->log = log_node;
1886           seg->region_size = region_size;
1887           seg->clustered = clustered;
1888           seg->mirror_area_count = area_count;
1889           seg->flags = flags;
1890 
1891           return 1;
1892 }
1893 
dm_tree_node_add_mirror_target(struct dm_tree_node * node,uint64_t size)1894 int dm_tree_node_add_mirror_target(struct dm_tree_node *node,
1895                                       uint64_t size)
1896 {
1897           struct load_segment *seg;
1898 
1899           if (!(seg = _add_segment(node, SEG_MIRRORED, size)))
1900                     return_0;
1901 
1902           return 1;
1903 }
1904 
_add_area(struct dm_tree_node * node,struct load_segment * seg,struct dm_tree_node * dev_node,uint64_t offset)1905 static int _add_area(struct dm_tree_node *node, struct load_segment *seg, struct dm_tree_node *dev_node, uint64_t offset)
1906 {
1907           struct seg_area *area;
1908 
1909           if (!(area = dm_pool_zalloc(node->dtree->mem, sizeof (*area)))) {
1910                     log_error("Failed to allocate target segment area.");
1911                     return 0;
1912           }
1913 
1914           area->dev_node = dev_node;
1915           area->offset = offset;
1916 
1917           dm_list_add(&seg->areas, &area->list);
1918           seg->area_count++;
1919 
1920           return 1;
1921 }
1922 
dm_tree_node_add_target_area(struct dm_tree_node * node,const char * dev_name,const char * uuid,uint64_t offset)1923 int dm_tree_node_add_target_area(struct dm_tree_node *node,
1924                                     const char *dev_name,
1925                                     const char *uuid,
1926                                     uint64_t offset)
1927 {
1928           struct load_segment *seg;
1929           struct stat info;
1930           struct dm_tree_node *dev_node;
1931 
1932           if ((!dev_name || !*dev_name) && (!uuid || !*uuid)) {
1933                     log_error("dm_tree_node_add_target_area called without device");
1934                     return 0;
1935           }
1936 
1937           if (uuid) {
1938                     if (!(dev_node = dm_tree_find_node_by_uuid(node->dtree, uuid))) {
1939                               log_error("Couldn't find area uuid %s.", uuid);
1940                               return 0;
1941                     }
1942                     if (!_link_tree_nodes(node, dev_node))
1943                               return_0;
1944           } else {
1945           if (stat(dev_name, &info) < 0) {
1946                               log_error("Device %s not found.", dev_name);
1947                               return 0;
1948                     }
1949 #if !defined(__NetBSD__) && !defined(__DragonFly__)
1950           if (!S_ISBLK(info.st_mode)) {
1951                               log_error("Device %s is not a block device.", dev_name);
1952                               return 0;
1953                     }
1954 #else
1955                     if (S_ISBLK(info.st_mode)) {
1956                               log_error("Device %s is a block device. Use raw devices on NetBSD.", dev_name);
1957                               return 0;
1958                     }
1959 #endif
1960                     /* FIXME Check correct macro use */
1961                     if (!(dev_node = _add_dev(node->dtree, node, MAJOR(info.st_rdev), MINOR(info.st_rdev))))
1962                               return_0;
1963           }
1964 
1965           if (!node->props.segment_count) {
1966                     log_error("Internal error: Attempt to add target area to missing segment.");
1967                     return 0;
1968           }
1969 
1970           seg = dm_list_item(dm_list_last(&node->props.segs), struct load_segment);
1971 
1972           if (!_add_area(node, seg, dev_node, offset))
1973                     return_0;
1974 
1975           return 1;
1976 }
1977 
dm_tree_set_cookie(struct dm_tree_node * node,uint32_t cookie)1978 void dm_tree_set_cookie(struct dm_tree_node *node, uint32_t cookie)
1979 {
1980           node->dtree->cookie = cookie;
1981 }
1982 
dm_tree_get_cookie(struct dm_tree_node * node)1983 uint32_t dm_tree_get_cookie(struct dm_tree_node *node)
1984 {
1985           return node->dtree->cookie;
1986 }
1987