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