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