]> sourceware.org Git - lvm2.git/blame - libdm/libdm-deptree.c
Use dm_is_dm_major instead of local copy.
[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
26struct deptree_node {
27 struct deptree *deptree;
28
29 const char *name;
30 const char *uuid;
31 struct dm_info info;
32
33 struct list uses; /* Nodes this node uses */
34 struct list used_by; /* Nodes that use this node */
35};
36
37struct deptree {
a3f6b2ce
AK
38 struct dm_pool *mem;
39 struct dm_hash_table *devs;
3d0480ed
AK
40 struct deptree_node root;
41};
42
43struct deptree_link {
44 struct list list;
45 struct deptree_node *node;
46};
47
48struct deptree *dm_deptree_create(void)
49{
50 struct deptree *deptree;
51
a3f6b2ce 52 if (!(deptree = dm_malloc(sizeof(*deptree)))) {
3d0480ed
AK
53 log_error("dm_deptree_create malloc failed");
54 return NULL;
55 }
56
57 memset(deptree, 0, sizeof(*deptree));
58 deptree->root.deptree = deptree;
59 list_init(&deptree->root.uses);
60 list_init(&deptree->root.used_by);
61
a3f6b2ce 62 if (!(deptree->mem = dm_pool_create("deptree", 1024))) {
3d0480ed 63 log_error("deptree pool creation failed");
a3f6b2ce 64 dm_free(deptree);
3d0480ed
AK
65 return NULL;
66 }
67
a3f6b2ce 68 if (!(deptree->devs = dm_hash_create(8))) {
3d0480ed 69 log_error("deptree hash creation failed");
a3f6b2ce
AK
70 dm_pool_destroy(deptree->mem);
71 dm_free(deptree);
3d0480ed
AK
72 return NULL;
73 }
74
75 return deptree;
76}
77
78void dm_deptree_free(struct deptree *deptree)
79{
80 if (!deptree)
81 return;
82
a3f6b2ce
AK
83 dm_hash_destroy(deptree->devs);
84 dm_pool_destroy(deptree->mem);
85 dm_free(deptree);
3d0480ed
AK
86}
87
88static int _nodes_are_linked(struct deptree_node *parent,
89 struct deptree_node *child)
90{
91 struct deptree_link *dlink;
92
93 list_iterate_items(dlink, &parent->uses) {
94 if (dlink->node == child)
95 return 1;
96 }
97
98 return 0;
99}
100
101static int _link(struct list *list, struct deptree_node *node)
102{
103 struct deptree_link *dlink;
104
a3f6b2ce 105 if (!(dlink = dm_pool_alloc(node->deptree->mem, sizeof(*dlink)))) {
3d0480ed
AK
106 log_error("deptree link allocation failed");
107 return 0;
108 }
109
110 dlink->node = node;
111 list_add(list, &dlink->list);
112
113 return 1;
114}
115
116static int _link_nodes(struct deptree_node *parent,
117 struct deptree_node *child)
118{
119 if (_nodes_are_linked(parent, child))
120 return 1;
121
122 if (!_link(&parent->uses, child))
123 return 0;
124
125 if (!_link(&child->used_by, parent))
126 return 0;
127
128 return 1;
129}
130
131static void _unlink(struct list *list, struct deptree_node *node)
132{
133 struct deptree_link *dlink;
134
135 list_iterate_items(dlink, list) {
136 if (dlink->node == node) {
137 list_del(&dlink->list);
138 break;
139 }
140 }
141}
142
143static void _unlink_nodes(struct deptree_node *parent,
144 struct deptree_node *child)
145{
146 if (!_nodes_are_linked(parent, child))
147 return;
148
149 _unlink(&parent->uses, child);
150 _unlink(&child->used_by, parent);
151}
152
153static void _remove_from_toplevel(struct deptree_node *node)
154{
155 return _unlink_nodes(&node->deptree->root, node);
156}
157
158static int _add_to_bottomlevel(struct deptree_node *node)
159{
160 return _link_nodes(node, &node->deptree->root);
161}
162
163static struct deptree_node *_create_deptree_node(struct deptree *deptree,
164 struct deptree_node *parent,
165 const char *name,
166 const char *uuid,
167 struct dm_info *info)
168{
169 struct deptree_node *node;
170 uint64_t dev;
171
a3f6b2ce 172 if (!(node = dm_pool_zalloc(deptree->mem, sizeof(*node)))) {
3d0480ed
AK
173 log_error("_create_deptree_node alloc failed");
174 return NULL;
175 }
176
177 node->deptree = deptree;
178
179 node->name = name;
180 node->uuid = uuid;
181 node->info = *info;
182
183 list_init(&node->uses);
184 list_init(&node->used_by);
185
186 dev = MKDEV(info->major, info->minor);
187
a3f6b2ce 188 if (!dm_hash_insert_binary(deptree->devs, (const char *) &dev,
3d0480ed
AK
189 sizeof(dev), node)) {
190 log_error("deptree node hash insertion failed");
a3f6b2ce 191 dm_pool_free(deptree->mem, node);
3d0480ed
AK
192 return NULL;
193 }
194
195 return node;
196}
197
198static struct deptree_node *_find_deptree_node(struct deptree *deptree,
199 uint32_t major, uint32_t minor)
200{
201 uint64_t dev = MKDEV(major, minor);
202
a3f6b2ce 203 return dm_hash_lookup_binary(deptree->devs, (const char *) &dev,
3d0480ed
AK
204 sizeof(dev));
205}
206
a3f6b2ce 207static int _deps(struct dm_task **dmt, struct dm_pool *mem, uint32_t major, uint32_t minor,
3d0480ed
AK
208 const char **name, const char **uuid,
209 struct dm_info *info, struct dm_deps **deps)
210{
211 memset(info, 0, sizeof(*info));
212
213 if (!dm_is_dm_major(major)) {
214 *name = "";
215 *uuid = "";
216 *deps = NULL;
217 info->major = major;
218 info->minor = minor;
219 info->exists = 0;
220 return 1;
221 }
222
223 if (!(*dmt = dm_task_create(DM_DEVICE_DEPS))) {
224 log_error("deps dm_task creation failed");
225 return 0;
226 }
227
228 if (!dm_task_set_major(*dmt, major))
229 goto failed;
230
231 if (!dm_task_set_minor(*dmt, minor))
232 goto failed;
233
234 if (!dm_task_run(*dmt))
235 goto failed;
236
237 if (!dm_task_get_info(*dmt, info))
238 goto failed;
239
240 if (!info->exists) {
241 *name = "";
242 *uuid = "";
243 *deps = NULL;
244 } else {
245 if (info->major != major) {
246 log_error("Inconsistent deptree major number: %u != %u",
247 major, info->major);
248 goto failed;
249 }
250 if (info->minor != minor) {
251 log_error("Inconsistent deptree minor number: %u != %u",
252 minor, info->minor);
253 goto failed;
254 }
a3f6b2ce 255 if (!(*name = dm_pool_strdup(mem, dm_task_get_name(*dmt)))) {
3d0480ed
AK
256 log_error("name pool_strdup failed");
257 goto failed;
258 }
a3f6b2ce 259 if (!(*uuid = dm_pool_strdup(mem, dm_task_get_uuid(*dmt)))) {
3d0480ed
AK
260 log_error("uuid pool_strdup failed");
261 goto failed;
262 }
263 *deps = dm_task_get_deps(*dmt);
264 }
265
266 return 1;
267
268failed:
269 dm_task_destroy(*dmt);
270 return 0;
271}
272
273static int _add_dev(struct deptree *deptree, struct deptree_node *parent,
274 uint32_t major, uint32_t minor)
275{
276 struct dm_task *dmt = NULL;
277 struct dm_info info;
278 struct dm_deps *deps = NULL;
279 const char *name = NULL;
280 const char *uuid = NULL;
281 struct deptree_node *node;
282 uint32_t i;
283 int r = 0;
284 int new = 0;
285
286 /* Already in tree? */
287 if (!(node = _find_deptree_node(deptree, major, minor))) {
288 if (!_deps(&dmt, deptree->mem, major, minor, &name, &uuid, &info, &deps))
289 return 0;
290
291 if (!(node = _create_deptree_node(deptree, node, name, uuid,
292 &info)))
293 goto out;
294 new = 1;
295 }
296
297 /* If new parent not root node, remove any existing root node parent */
298 if (parent != &deptree->root)
299 _remove_from_toplevel(node);
300
301 /* Create link to parent. Use root node only if no other parents. */
302 if ((parent != &deptree->root) || !dm_deptree_node_num_children(node, 1))
303 if (!_link_nodes(parent, node))
304 goto out;
305
306 /* If node was already in tree, no need to recurse. */
307 if (!new)
308 return 1;
309
310 /* Can't recurse if not a mapped device or there are no dependencies */
311 if (!node->info.exists || !deps->count) {
312 if (!_add_to_bottomlevel(node))
313 goto out;
314 return 1;
315 }
316
317 /* Add dependencies to tree */
318 for (i = 0; i < deps->count; i++)
319 if (!_add_dev(deptree, node, MAJOR(deps->device[i]),
320 MINOR(deps->device[i])))
321 goto out;
322
323 r = 1;
324out:
325 if (dmt)
326 dm_task_destroy(dmt);
327
328 return r;
329}
330
331int dm_deptree_add_dev(struct deptree *deptree, uint32_t major, uint32_t minor)
332{
333 return _add_dev(deptree, &deptree->root, major, minor);
334}
335
336const char *dm_deptree_node_get_name(struct deptree_node *node)
337{
338 return node->info.exists ? node->name : "";
339}
340
341const char *dm_deptree_node_get_uuid(struct deptree_node *node)
342{
343 return node->info.exists ? node->uuid : "";
344}
345
346const struct dm_info *dm_deptree_node_get_info(struct deptree_node *node)
347{
348 return &node->info;
349}
350
351int dm_deptree_node_num_children(struct deptree_node *node, uint32_t inverted)
352{
353 if (inverted) {
354 if (_nodes_are_linked(&node->deptree->root, node))
355 return 0;
356 return list_size(&node->used_by);
357 }
358
359 if (_nodes_are_linked(node, &node->deptree->root))
360 return 0;
361
362 return list_size(&node->uses);
363}
364
365/*
366 * Set major and minor to zero for root of tree.
367 */
368struct deptree_node *dm_deptree_find_node(struct deptree *deptree,
369 uint32_t major,
370 uint32_t minor)
371{
372 if (!major && !minor)
373 return &deptree->root;
374
375 return _find_deptree_node(deptree, major, minor);
376}
377
378/*
379 * First time set *handle to NULL.
380 * Set inverted to invert the tree.
381 */
382struct deptree_node *dm_deptree_next_child(void **handle,
383 struct deptree_node *parent,
384 uint32_t inverted)
385{
386 struct list **dlink = (struct list **) handle;
387 struct list *use_list;
388
389 if (inverted)
390 use_list = &parent->used_by;
391 else
392 use_list = &parent->uses;
393
394 if (!*dlink)
395 *dlink = list_first(use_list);
396 else
397 *dlink = list_next(use_list, *dlink);
398
399 return (*dlink) ? list_item(*dlink, struct deptree_link)->node : NULL;
400}
401
3e8c6b73 402/*
a6d97ede 403 * Deactivate a device with its dependencies if the uuid prefix matches.
3e8c6b73
AK
404 */
405static int _info_by_dev(uint32_t major, uint32_t minor, struct dm_info *info)
406{
407 struct dm_task *dmt;
408 int r;
409
410 if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
411 log_error("_info_by_dev: dm_task creation failed");
412 return 0;
413 }
414
415 if (!dm_task_set_major(dmt, major) || !dm_task_set_minor(dmt, minor)) {
416 log_error("_info_by_dev: Failed to set device number");
417 dm_task_destroy(dmt);
418 return 0;
419 }
420
421 if ((r = dm_task_run(dmt)))
422 r = dm_task_get_info(dmt, info);
423
424 dm_task_destroy(dmt);
425
426 return r;
427}
428
429static int _deactivate_node(const char *name, uint32_t major, uint32_t minor)
430{
431 struct dm_task *dmt;
432 int r;
433
434 log_verbose("Removing %s (%" PRIu32 ":%" PRIu32 ")", name, major, minor);
435
436 if (!(dmt = dm_task_create(DM_DEVICE_REMOVE))) {
437 log_error("Deactivation dm_task creation failed for %s", name);
438 return 0;
439 }
440
441 if (!dm_task_set_major(dmt, major) || !dm_task_set_minor(dmt, minor)) {
442 log_error("Failed to set device number for %s deactivation", name);
443 dm_task_destroy(dmt);
444 return 0;
445 }
446
447 if (!dm_task_no_open_count(dmt))
448 log_error("Failed to disable open_count");
449
450 r = dm_task_run(dmt);
451
452 dm_task_destroy(dmt);
453
454 return r;
455}
456
a6d97ede
AK
457int dm_deptree_deactivate_children(struct deptree_node *dnode,
458 const char *uuid_prefix,
459 size_t uuid_prefix_len)
3e8c6b73
AK
460{
461 void *handle = NULL;
462 struct deptree_node *child = dnode;
463 struct dm_info info;
464 const struct dm_info *dinfo;
465 const char *name;
466 const char *uuid;
467
468 while ((child = dm_deptree_next_child(&handle, dnode, 0))) {
469 if (!(dinfo = dm_deptree_node_get_info(child))) {
470 stack;
471 continue;
472 }
473
474 if (!(name = dm_deptree_node_get_name(child))) {
475 stack;
476 continue;
477 }
478
479 if (!(uuid = dm_deptree_node_get_uuid(child))) {
480 stack;
481 continue;
482 }
483
484 /* Ignore if it doesn't belong to this VG */
a6d97ede 485 if (uuid_prefix && strncmp(uuid, uuid_prefix, uuid_prefix_len))
3e8c6b73 486 continue;
3e8c6b73
AK
487
488 /* Refresh open_count */
489 if (!_info_by_dev(dinfo->major, dinfo->minor, &info) ||
490 !info.exists || info.open_count)
491 continue;
492
493 if (!_deactivate_node(name, info.major, info.minor)) {
494 log_error("Unable to deactivate %s (%" PRIu32
495 ":%" PRIu32 ")", name, info.major,
496 info.minor);
497 continue;
498 }
499
500 if (dm_deptree_node_num_children(child, 0))
501 dm_deptree_deactivate_children(child, uuid_prefix, uuid_prefix_len);
502 }
503
504 return 1;
505}
This page took 0.069357 seconds and 5 git commands to generate.