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