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