]> sourceware.org Git - lvm2.git/blame - libdm/libdm-deptree.c
Avoid a dmeventd compiler warning.
[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
165e4a11 1245 if (seg->clustered) {
67b25ed4
AK
1246 if (seg->uuid)
1247 log_parm_count++; /* uuid */
90a34450 1248 if ((tw = _dm_snprintf(params + pos, paramsize - pos, "clustered_")) < 0) {
b4f1578f 1249 stack; /* Out of space */
165e4a11
AK
1250 return -1;
1251 }
1252 pos += tw;
1253 }
dbcb64b8 1254
dbcb64b8
AK
1255 if (!seg->log)
1256 logtype = "core";
1257 else {
1258 logtype = "disk";
1259 log_parm_count++;
b4f1578f
AK
1260 if (!_build_dev_string(logbuf, sizeof(logbuf), seg->log))
1261 return_0;
dbcb64b8
AK
1262 }
1263
1264 if ((tw = _dm_snprintf(params + pos, paramsize - pos, "%s %u ", logtype, log_parm_count)) < 0) {
1265 stack; /* Out of space */
1266 return -1;
1267 }
1268 pos += tw;
1269
1270 if (seg->log) {
1271 if ((tw = _dm_snprintf(params + pos, paramsize - pos, "%s ", logbuf)) < 0) {
b4f1578f 1272 stack; /* Out of space */
165e4a11
AK
1273 return -1;
1274 }
1275 pos += tw;
1276 }
dbcb64b8
AK
1277
1278 if ((tw = _dm_snprintf(params + pos, paramsize - pos, "%u ", seg->region_size)) < 0) {
b4f1578f 1279 stack; /* Out of space */
165e4a11
AK
1280 return -1;
1281 }
1282 pos += tw;
dbcb64b8 1283
67b25ed4
AK
1284 if (seg->clustered && seg->uuid) {
1285 if ((tw = _dm_snprintf(params + pos, paramsize - pos, "%s ", seg->uuid)) < 0) {
1286 stack; /* Out of space */
1287 return -1;
1288 }
1289 pos += tw;
1290 }
1291
dbcb64b8
AK
1292 if ((seg->flags & DM_NOSYNC)) {
1293 if ((tw = _dm_snprintf(params + pos, paramsize - pos, "nosync ")) < 0) {
1294 stack; /* Out of space */
1295 return -1;
1296 }
1297 pos += tw;
1298 } else if ((seg->flags & DM_FORCESYNC)) {
1299 if ((tw = _dm_snprintf(params + pos, paramsize - pos, "sync ")) < 0) {
1300 stack; /* Out of space */
1301 return -1;
1302 }
1303 pos += tw;
1304 }
1305
1306 if ((seg->flags & DM_BLOCK_ON_ERROR)) {
1307 if ((tw = _dm_snprintf(params + pos, paramsize - pos, "block_on_error ")) < 0) {
1308 stack; /* Out of space */
1309 return -1;
1310 }
1311 pos += tw;
1312 }
1313
1314 if ((tw = _dm_snprintf(params + pos, paramsize - pos, "%u ", seg->mirror_area_count)) < 0) {
1315 stack; /* Out of space */
1316 return -1;
1317 }
1318 pos += tw;
1319
165e4a11
AK
1320 break;
1321 case SEG_SNAPSHOT:
b4f1578f
AK
1322 if (!_build_dev_string(originbuf, sizeof(originbuf), seg->origin))
1323 return_0;
1324 if (!_build_dev_string(cowbuf, sizeof(cowbuf), seg->cow))
1325 return_0;
165e4a11
AK
1326 if ((pos = _dm_snprintf(params, paramsize, "%s %s %c %d",
1327 originbuf, cowbuf,
1328 seg->persistent ? 'P' : 'N',
1329 seg->chunk_size)) < 0) {
b4f1578f 1330 stack; /* Out of space */
165e4a11
AK
1331 return -1;
1332 }
1333 break;
1334 case SEG_SNAPSHOT_ORIGIN:
b4f1578f
AK
1335 if (!_build_dev_string(originbuf, sizeof(originbuf), seg->origin))
1336 return_0;
165e4a11
AK
1337 if ((pos = _dm_snprintf(params, paramsize, "%s",
1338 originbuf)) < 0) {
b4f1578f 1339 stack; /* Out of space */
165e4a11
AK
1340 return -1;
1341 }
1342 break;
1343 case SEG_STRIPED:
1344 if ((pos = _dm_snprintf(params, paramsize, "%u %u ",
1345 seg->area_count,
1346 seg->stripe_size)) < 0) {
b4f1578f 1347 stack; /* Out of space */
165e4a11
AK
1348 return -1;
1349 }
1350 break;
1351 }
1352
1353 switch(seg->type) {
1354 case SEG_ERROR:
1355 case SEG_SNAPSHOT:
1356 case SEG_SNAPSHOT_ORIGIN:
1357 case SEG_ZERO:
1358 break;
1359 case SEG_LINEAR:
1360 case SEG_MIRRORED:
1361 case SEG_STRIPED:
1362 if ((r = _emit_areas_line(dmt, seg, params, paramsize, &pos)) <= 0) {
1363 stack;
1364 return r;
1365 }
1366 break;
1367 }
1368
1369 log_debug("Adding target: %" PRIu64 " %" PRIu64 " %s %s",
1370 *seg_start, seg->size, dm_segtypes[seg->type].target, params);
1371
b4f1578f
AK
1372 if (!dm_task_add_target(dmt, *seg_start, seg->size, dm_segtypes[seg->type].target, params))
1373 return_0;
165e4a11
AK
1374
1375 *seg_start += seg->size;
1376
1377 return 1;
1378}
1379
1380static int _emit_segment(struct dm_task *dmt, struct load_segment *seg,
1381 uint64_t *seg_start)
1382{
1383 char *params;
1384 size_t paramsize = 4096;
1385 int ret;
1386
1387 do {
1388 if (!(params = dm_malloc(paramsize))) {
1389 log_error("Insufficient space for target parameters.");
1390 return 0;
1391 }
1392
1393 ret = _emit_segment_line(dmt, seg, seg_start, params, paramsize);
1394 dm_free(params);
1395
1396 if (!ret)
1397 stack;
1398
1399 if (ret >= 0)
1400 return ret;
1401
1402 log_debug("Insufficient space in params[%" PRIsize_t
1403 "] for target parameters.", paramsize);
1404
1405 paramsize *= 2;
1406 } while (paramsize < MAX_TARGET_PARAMSIZE);
1407
1408 log_error("Target parameter size too big. Aborting.");
1409 return 0;
1410}
1411
b4f1578f 1412static int _load_node(struct dm_tree_node *dnode)
165e4a11
AK
1413{
1414 int r = 0;
1415 struct dm_task *dmt;
1416 struct load_segment *seg;
1417 uint64_t seg_start = 0;
1418
1419 log_verbose("Loading %s table", dnode->name);
1420
1421 if (!(dmt = dm_task_create(DM_DEVICE_RELOAD))) {
1422 log_error("Reload dm_task creation failed for %s", dnode->name);
1423 return 0;
1424 }
1425
1426 if (!dm_task_set_major(dmt, dnode->info.major) ||
1427 !dm_task_set_minor(dmt, dnode->info.minor)) {
1428 log_error("Failed to set device number for %s reload.", dnode->name);
1429 goto out;
1430 }
1431
1432 if (dnode->props.read_only && !dm_task_set_ro(dmt)) {
1433 log_error("Failed to set read only flag for %s", dnode->name);
1434 goto out;
1435 }
1436
1437 if (!dm_task_no_open_count(dmt))
1438 log_error("Failed to disable open_count");
1439
1440 list_iterate_items(seg, &dnode->props.segs)
b4f1578f
AK
1441 if (!_emit_segment(dmt, seg, &seg_start))
1442 goto_out;
165e4a11 1443
ec289b64
AK
1444 if (!dm_task_suppress_identical_reload(dmt))
1445 log_error("Failed to suppress reload of identical tables.");
1446
1447 if ((r = dm_task_run(dmt))) {
165e4a11 1448 r = dm_task_get_info(dmt, &dnode->info);
ec289b64
AK
1449 if (r && !dnode->info.inactive_table)
1450 log_verbose("Suppressed %s identical table reload.",
1451 dnode->name);
1452 }
165e4a11
AK
1453
1454 dnode->props.segment_count = 0;
1455
1456out:
1457 dm_task_destroy(dmt);
1458
1459 return r;
165e4a11
AK
1460}
1461
b4f1578f 1462int dm_tree_preload_children(struct dm_tree_node *dnode,
165e4a11 1463 const char *uuid_prefix,
e6a6954e 1464 size_t uuid_prefix_len)
165e4a11
AK
1465{
1466 void *handle = NULL;
b4f1578f 1467 struct dm_tree_node *child;
165e4a11
AK
1468 struct dm_info newinfo;
1469 const char *name;
1470
1471 /* Preload children first */
b4f1578f 1472 while ((child = dm_tree_next_child(&handle, dnode, 0))) {
165e4a11
AK
1473 /* Skip existing non-device-mapper devices */
1474 if (!child->info.exists && child->info.major)
1475 continue;
1476
1477 /* Ignore if it doesn't belong to this VG */
87f98002
AK
1478 if (child->info.exists &&
1479 !_uuid_prefix_matches(child->uuid, uuid_prefix, uuid_prefix_len))
165e4a11
AK
1480 continue;
1481
b4f1578f 1482 if (dm_tree_node_num_children(child, 0))
e6a6954e 1483 dm_tree_preload_children(child, uuid_prefix, uuid_prefix_len);
165e4a11 1484
b4f1578f 1485 if (!(name = dm_tree_node_get_name(child))) {
165e4a11
AK
1486 stack;
1487 continue;
1488 }
1489
1490 /* FIXME Cope if name exists with no uuid? */
1491 if (!child->info.exists) {
1492 if (!_create_node(child)) {
1493 stack;
1494 return 0;
1495 }
1496 }
1497
1498 if (!child->info.inactive_table && child->props.segment_count) {
1499 if (!_load_node(child)) {
1500 stack;
1501 return 0;
1502 }
1503 }
1504
1505 /* Resume device immediately if it has parents */
abbca212 1506 if (!dm_tree_node_num_children(child, 1))
165e4a11
AK
1507 continue;
1508
7707ea90
AK
1509 if (!child->info.inactive_table && !child->info.suspended)
1510 continue;
1511
165e4a11
AK
1512 if (!_resume_node(name, child->info.major, child->info.minor, &newinfo)) {
1513 log_error("Unable to resume %s (%" PRIu32
1514 ":%" PRIu32 ")", name, child->info.major,
1515 child->info.minor);
1516 continue;
1517 }
1518
1519 /* Update cached info */
1520 child->info = newinfo;
1521 }
1522
1523 handle = NULL;
1524
1525 return 1;
1526}
1527
165e4a11
AK
1528/*
1529 * Returns 1 if unsure.
1530 */
b4f1578f 1531int dm_tree_children_use_uuid(struct dm_tree_node *dnode,
165e4a11
AK
1532 const char *uuid_prefix,
1533 size_t uuid_prefix_len)
1534{
1535 void *handle = NULL;
b4f1578f 1536 struct dm_tree_node *child = dnode;
165e4a11
AK
1537 const char *uuid;
1538
b4f1578f
AK
1539 while ((child = dm_tree_next_child(&handle, dnode, 0))) {
1540 if (!(uuid = dm_tree_node_get_uuid(child))) {
1541 log_error("Failed to get uuid for dtree node.");
165e4a11
AK
1542 return 1;
1543 }
1544
87f98002 1545 if (_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
165e4a11
AK
1546 return 1;
1547
b4f1578f
AK
1548 if (dm_tree_node_num_children(child, 0))
1549 dm_tree_children_use_uuid(child, uuid_prefix, uuid_prefix_len);
165e4a11
AK
1550 }
1551
1552 return 0;
1553}
1554
1555/*
1556 * Target functions
1557 */
b4f1578f 1558static struct load_segment *_add_segment(struct dm_tree_node *dnode, unsigned type, uint64_t size)
165e4a11
AK
1559{
1560 struct load_segment *seg;
1561
b4f1578f
AK
1562 if (!(seg = dm_pool_zalloc(dnode->dtree->mem, sizeof(*seg)))) {
1563 log_error("dtree node segment allocation failed");
165e4a11
AK
1564 return NULL;
1565 }
1566
1567 seg->type = type;
1568 seg->size = size;
1569 seg->area_count = 0;
1570 list_init(&seg->areas);
1571 seg->stripe_size = 0;
1572 seg->persistent = 0;
1573 seg->chunk_size = 0;
1574 seg->cow = NULL;
1575 seg->origin = NULL;
1576
1577 list_add(&dnode->props.segs, &seg->list);
1578 dnode->props.segment_count++;
1579
1580 return seg;
1581}
1582
b4f1578f 1583int dm_tree_node_add_snapshot_origin_target(struct dm_tree_node *dnode,
165e4a11
AK
1584 uint64_t size,
1585 const char *origin_uuid)
1586{
1587 struct load_segment *seg;
b4f1578f 1588 struct dm_tree_node *origin_node;
165e4a11 1589
b4f1578f
AK
1590 if (!(seg = _add_segment(dnode, SEG_SNAPSHOT_ORIGIN, size)))
1591 return_0;
165e4a11 1592
b4f1578f 1593 if (!(origin_node = dm_tree_find_node_by_uuid(dnode->dtree, origin_uuid))) {
165e4a11
AK
1594 log_error("Couldn't find snapshot origin uuid %s.", origin_uuid);
1595 return 0;
1596 }
1597
1598 seg->origin = origin_node;
b4f1578f
AK
1599 if (!_link_tree_nodes(dnode, origin_node))
1600 return_0;
165e4a11 1601
56c28292
AK
1602 /* Resume snapshot origins after new snapshots */
1603 dnode->activation_priority = 1;
1604
165e4a11
AK
1605 return 1;
1606}
1607
b4f1578f 1608int dm_tree_node_add_snapshot_target(struct dm_tree_node *node,
165e4a11
AK
1609 uint64_t size,
1610 const char *origin_uuid,
1611 const char *cow_uuid,
1612 int persistent,
1613 uint32_t chunk_size)
1614{
1615 struct load_segment *seg;
b4f1578f 1616 struct dm_tree_node *origin_node, *cow_node;
165e4a11 1617
b4f1578f
AK
1618 if (!(seg = _add_segment(node, SEG_SNAPSHOT, size)))
1619 return_0;
165e4a11 1620
b4f1578f 1621 if (!(origin_node = dm_tree_find_node_by_uuid(node->dtree, origin_uuid))) {
165e4a11
AK
1622 log_error("Couldn't find snapshot origin uuid %s.", origin_uuid);
1623 return 0;
1624 }
1625
1626 seg->origin = origin_node;
b4f1578f
AK
1627 if (!_link_tree_nodes(node, origin_node))
1628 return_0;
165e4a11 1629
b4f1578f 1630 if (!(cow_node = dm_tree_find_node_by_uuid(node->dtree, cow_uuid))) {
165e4a11
AK
1631 log_error("Couldn't find snapshot origin uuid %s.", cow_uuid);
1632 return 0;
1633 }
1634
1635 seg->cow = cow_node;
b4f1578f
AK
1636 if (!_link_tree_nodes(node, cow_node))
1637 return_0;
165e4a11
AK
1638
1639 seg->persistent = persistent ? 1 : 0;
1640 seg->chunk_size = chunk_size;
1641
1642 return 1;
1643}
1644
b4f1578f 1645int dm_tree_node_add_error_target(struct dm_tree_node *node,
165e4a11
AK
1646 uint64_t size)
1647{
b4f1578f
AK
1648 if (!_add_segment(node, SEG_ERROR, size))
1649 return_0;
165e4a11
AK
1650
1651 return 1;
1652}
1653
b4f1578f 1654int dm_tree_node_add_zero_target(struct dm_tree_node *node,
165e4a11
AK
1655 uint64_t size)
1656{
b4f1578f
AK
1657 if (!_add_segment(node, SEG_ZERO, size))
1658 return_0;
165e4a11
AK
1659
1660 return 1;
1661}
1662
b4f1578f 1663int dm_tree_node_add_linear_target(struct dm_tree_node *node,
165e4a11
AK
1664 uint64_t size)
1665{
b4f1578f
AK
1666 if (!_add_segment(node, SEG_LINEAR, size))
1667 return_0;
165e4a11
AK
1668
1669 return 1;
1670}
1671
b4f1578f 1672int dm_tree_node_add_striped_target(struct dm_tree_node *node,
165e4a11
AK
1673 uint64_t size,
1674 uint32_t stripe_size)
1675{
1676 struct load_segment *seg;
1677
b4f1578f
AK
1678 if (!(seg = _add_segment(node, SEG_STRIPED, size)))
1679 return_0;
165e4a11
AK
1680
1681 seg->stripe_size = stripe_size;
1682
1683 return 1;
1684}
1685
b4f1578f 1686int dm_tree_node_add_mirror_target_log(struct dm_tree_node *node,
165e4a11
AK
1687 uint32_t region_size,
1688 unsigned clustered,
1689 const char *log_uuid,
ce7ed2c0
AK
1690 unsigned area_count,
1691 uint32_t flags)
165e4a11 1692{
908db078 1693 struct dm_tree_node *log_node = NULL;
165e4a11
AK
1694 struct load_segment *seg;
1695
1696 if (!node->props.segment_count) {
1697 log_error("Internal error: Attempt to add target area to missing segment.");
1698 return 0;
1699 }
1700
1701 seg = list_item(list_last(&node->props.segs), struct load_segment);
1702
24b026e3
AK
1703 if (log_uuid) {
1704 if (!(log_node = dm_tree_find_node_by_uuid(node->dtree, log_uuid))) {
1705 log_error("Couldn't find mirror log uuid %s.", log_uuid);
1706 return 0;
1707 }
67b25ed4 1708
24b026e3
AK
1709 if (!_link_tree_nodes(node, log_node))
1710 return_0;
67b25ed4
AK
1711
1712 if (!(seg->uuid = dm_pool_strdup(node->dtree->mem, log_uuid))) {
1713 log_error("log uuid pool_strdup failed");
1714 return 0;
1715 }
165e4a11
AK
1716 }
1717
1718 seg->log = log_node;
165e4a11
AK
1719 seg->region_size = region_size;
1720 seg->clustered = clustered;
1721 seg->mirror_area_count = area_count;
dbcb64b8 1722 seg->flags = flags;
165e4a11
AK
1723
1724 return 1;
1725}
1726
b4f1578f 1727int dm_tree_node_add_mirror_target(struct dm_tree_node *node,
165e4a11
AK
1728 uint64_t size)
1729{
1730 struct load_segment *seg;
1731
b4f1578f
AK
1732 if (!(seg = _add_segment(node, SEG_MIRRORED, size)))
1733 return_0;
165e4a11
AK
1734
1735 return 1;
1736}
1737
b4f1578f 1738static int _add_area(struct dm_tree_node *node, struct load_segment *seg, struct dm_tree_node *dev_node, uint64_t offset)
165e4a11
AK
1739{
1740 struct seg_area *area;
1741
b4f1578f 1742 if (!(area = dm_pool_zalloc(node->dtree->mem, sizeof (*area)))) {
165e4a11
AK
1743 log_error("Failed to allocate target segment area.");
1744 return 0;
1745 }
1746
1747 area->dev_node = dev_node;
1748 area->offset = offset;
1749
1750 list_add(&seg->areas, &area->list);
1751 seg->area_count++;
1752
1753 return 1;
1754}
1755
b4f1578f 1756int dm_tree_node_add_target_area(struct dm_tree_node *node,
165e4a11
AK
1757 const char *dev_name,
1758 const char *uuid,
1759 uint64_t offset)
1760{
1761 struct load_segment *seg;
1762 struct stat info;
b4f1578f 1763 struct dm_tree_node *dev_node;
165e4a11
AK
1764
1765 if ((!dev_name || !*dev_name) && (!uuid || !*uuid)) {
b4f1578f 1766 log_error("dm_tree_node_add_target_area called without device");
165e4a11
AK
1767 return 0;
1768 }
1769
1770 if (uuid) {
b4f1578f 1771 if (!(dev_node = dm_tree_find_node_by_uuid(node->dtree, uuid))) {
165e4a11
AK
1772 log_error("Couldn't find area uuid %s.", uuid);
1773 return 0;
1774 }
b4f1578f
AK
1775 if (!_link_tree_nodes(node, dev_node))
1776 return_0;
165e4a11
AK
1777 } else {
1778 if (stat(dev_name, &info) < 0) {
1779 log_error("Device %s not found.", dev_name);
1780 return 0;
1781 }
1782
1783 if (!S_ISBLK(info.st_mode)) {
1784 log_error("Device %s is not a block device.", dev_name);
1785 return 0;
1786 }
1787
1788 /* FIXME Check correct macro use */
b4f1578f
AK
1789 if (!(dev_node = _add_dev(node->dtree, node, MAJOR(info.st_rdev), MINOR(info.st_rdev))))
1790 return_0;
165e4a11
AK
1791 }
1792
1793 if (!node->props.segment_count) {
1794 log_error("Internal error: Attempt to add target area to missing segment.");
1795 return 0;
1796 }
1797
1798 seg = list_item(list_last(&node->props.segs), struct load_segment);
1799
b4f1578f
AK
1800 if (!_add_area(node, seg, dev_node, offset))
1801 return_0;
165e4a11
AK
1802
1803 return 1;
db208f51 1804}
This page took 0.23348 seconds and 5 git commands to generate.