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