Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
3 : : * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
4 : : *
5 : : * This file is part of LVM2.
6 : : *
7 : : * This copyrighted material is made available to anyone wishing to use,
8 : : * modify, copy, or redistribute it subject to the terms and conditions
9 : : * of the GNU Lesser General Public License v.2.1.
10 : : *
11 : : * You should have received a copy of the GNU Lesser General Public License
12 : : * along with this program; if not, write to the Free Software Foundation,
13 : : * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 : : */
15 : :
16 : : #include "lib.h"
17 : : #include "str_list.h"
18 : : #include "dev_manager.h"
19 : : #include "lvm-string.h"
20 : : #include "fs.h"
21 : : #include "defaults.h"
22 : : #include "segtype.h"
23 : : #include "display.h"
24 : : #include "toolcontext.h"
25 : : #include "targets.h"
26 : : #include "config.h"
27 : : #include "filter.h"
28 : : #include "activate.h"
29 : :
30 : : #include <limits.h>
31 : : #include <dirent.h>
32 : :
33 : : #define MAX_TARGET_PARAMSIZE 50000
34 : : #define UUID_PREFIX "LVM-"
35 : :
36 : : typedef enum {
37 : : PRELOAD,
38 : : ACTIVATE,
39 : : DEACTIVATE,
40 : : SUSPEND,
41 : : SUSPEND_WITH_LOCKFS,
42 : : CLEAN
43 : : } action_t;
44 : :
45 : : struct dev_manager {
46 : : struct dm_pool *mem;
47 : :
48 : : struct cmd_context *cmd;
49 : :
50 : : void *target_state;
51 : : uint32_t pvmove_mirror_count;
52 : : int flush_required;
53 : :
54 : : char *vg_name;
55 : : };
56 : :
57 : : struct lv_layer {
58 : : struct logical_volume *lv;
59 : : const char *old_name;
60 : : };
61 : :
62 : 0 : static char *_build_dlid(struct dm_pool *mem, const char *lvid, const char *layer)
63 : : {
64 : : char *dlid;
65 : : size_t len;
66 : :
67 [ # # ]: 0 : if (!layer)
68 : 0 : layer = "";
69 : :
70 : 0 : len = sizeof(UUID_PREFIX) + sizeof(union lvid) + strlen(layer);
71 : :
72 [ # # ]: 0 : if (!(dlid = dm_pool_alloc(mem, len))) {
73 : 0 : log_error("_build_dlid: pool allocation failed for %" PRIsize_t
74 : : " %s %s.", len, lvid, layer);
75 : 0 : return NULL;
76 : : }
77 : :
78 [ # # ]: 0 : sprintf(dlid, UUID_PREFIX "%s%s%s", lvid, (*layer) ? "-" : "", layer);
79 : :
80 : 0 : return dlid;
81 : : }
82 : :
83 : 0 : char *build_dlid(struct dev_manager *dm, const char *lvid, const char *layer)
84 : : {
85 : 0 : return _build_dlid(dm->mem, lvid, layer);
86 : : }
87 : :
88 : 0 : static int _read_only_lv(struct logical_volume *lv)
89 : : {
90 [ # # ][ # # ]: 0 : return (!(lv->vg->status & LVM_WRITE) || !(lv->status & LVM_WRITE));
91 : : }
92 : :
93 : : /*
94 : : * Low level device-layer operations.
95 : : */
96 : 0 : static struct dm_task *_setup_task(const char *name, const char *uuid,
97 : : uint32_t *event_nr, int task,
98 : : uint32_t major, uint32_t minor)
99 : : {
100 : : struct dm_task *dmt;
101 : :
102 [ # # ]: 0 : if (!(dmt = dm_task_create(task)))
103 : 0 : return_NULL;
104 : :
105 [ # # ]: 0 : if (name)
106 : 0 : dm_task_set_name(dmt, name);
107 : :
108 [ # # ][ # # ]: 0 : if (uuid && *uuid)
109 : 0 : dm_task_set_uuid(dmt, uuid);
110 : :
111 [ # # ]: 0 : if (event_nr)
112 : 0 : dm_task_set_event_nr(dmt, *event_nr);
113 : :
114 [ # # ]: 0 : if (major)
115 : 0 : dm_task_set_major_minor(dmt, major, minor, 1);
116 : :
117 : 0 : return dmt;
118 : : }
119 : :
120 : 0 : static int _info_run(const char *name, const char *dlid, struct dm_info *info,
121 : : uint32_t *read_ahead, int mknodes, int with_open_count,
122 : : int with_read_ahead, uint32_t major, uint32_t minor)
123 : : {
124 : 0 : int r = 0;
125 : : struct dm_task *dmt;
126 : : int dmtask;
127 : :
128 [ # # ]: 0 : dmtask = mknodes ? DM_DEVICE_MKNODES : DM_DEVICE_INFO;
129 : :
130 [ # # ][ # # ]: 0 : if (!(dmt = _setup_task(mknodes ? name : NULL, dlid, 0, dmtask, major, minor)))
131 : 0 : return_0;
132 : :
133 [ # # ]: 0 : if (!with_open_count)
134 [ # # ]: 0 : if (!dm_task_no_open_count(dmt))
135 : 0 : log_error("Failed to disable open_count");
136 : :
137 [ # # ]: 0 : if (!dm_task_run(dmt))
138 : 0 : goto_out;
139 : :
140 [ # # ]: 0 : if (!dm_task_get_info(dmt, info))
141 : 0 : goto_out;
142 : :
143 [ # # ][ # # ]: 0 : if (with_read_ahead && info->exists) {
144 [ # # ]: 0 : if (!dm_task_get_read_ahead(dmt, read_ahead))
145 : 0 : goto_out;
146 [ # # ]: 0 : } else if (read_ahead)
147 : 0 : *read_ahead = DM_READ_AHEAD_NONE;
148 : :
149 : 0 : r = 1;
150 : :
151 : : out:
152 : 0 : dm_task_destroy(dmt);
153 : 0 : return r;
154 : : }
155 : :
156 : 0 : int device_is_usable(dev_t dev)
157 : : {
158 : : struct dm_task *dmt;
159 : : struct dm_info info;
160 : : const char *name;
161 : : uint64_t start, length;
162 : 0 : char *target_type = NULL;
163 : : char *params;
164 : 0 : void *next = NULL;
165 : 0 : int r = 0;
166 : :
167 [ # # ]: 0 : if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) {
168 : 0 : log_error("Failed to allocate dm_task struct to check dev status");
169 : 0 : return 0;
170 : : }
171 : :
172 [ # # ]: 0 : if (!dm_task_set_major_minor(dmt, MAJOR(dev), MINOR(dev), 1))
173 : 0 : goto_out;
174 : :
175 [ # # ]: 0 : if (!dm_task_run(dmt)) {
176 : 0 : log_error("Failed to get state of mapped device");
177 : 0 : goto out;
178 : : }
179 : :
180 [ # # ]: 0 : if (!dm_task_get_info(dmt, &info))
181 : 0 : goto_out;
182 : :
183 [ # # ][ # # ]: 0 : if (!info.exists || info.suspended)
184 : : goto out;
185 : :
186 : 0 : name = dm_task_get_name(dmt);
187 : :
188 : : /* FIXME Also check for mirror block_on_error and mpath no paths */
189 : : /* For now, we exclude all mirrors */
190 : :
191 : : do {
192 : 0 : next = dm_get_next_target(dmt, next, &start, &length,
193 : : &target_type, ¶ms);
194 : : /* Skip if target type doesn't match */
195 [ # # # # ]: 0 : if (target_type && !strcmp(target_type, "mirror"))
196 : 0 : goto out;
197 [ # # ]: 0 : } while (next);
198 : :
199 : : /* FIXME Also check dependencies? */
200 : :
201 : 0 : r = 1;
202 : :
203 : : out:
204 : 0 : dm_task_destroy(dmt);
205 : 0 : return r;
206 : : }
207 : :
208 : 0 : static int _info(const char *dlid, int with_open_count, int with_read_ahead,
209 : : struct dm_info *info, uint32_t *read_ahead)
210 : : {
211 : 0 : int r = 0;
212 : :
213 [ # # ][ # # ]: 0 : if ((r = _info_run(NULL, dlid, info, read_ahead, 0, with_open_count,
214 : 0 : with_read_ahead, 0, 0)) && info->exists)
215 : 0 : return 1;
216 [ # # ][ # # ]: 0 : else if ((r = _info_run(NULL, dlid + sizeof(UUID_PREFIX) - 1, info,
217 : : read_ahead, 0, with_open_count,
218 : 0 : with_read_ahead, 0, 0)) && info->exists)
219 : 0 : return 1;
220 : :
221 : 0 : return r;
222 : : }
223 : :
224 : 0 : static int _info_by_dev(uint32_t major, uint32_t minor, struct dm_info *info)
225 : : {
226 : 0 : return _info_run(NULL, NULL, info, NULL, 0, 0, 0, major, minor);
227 : : }
228 : :
229 : 0 : int dev_manager_info(struct dm_pool *mem, const struct logical_volume *lv,
230 : : int with_open_count, int with_read_ahead,
231 : : struct dm_info *info, uint32_t *read_ahead)
232 : : {
233 : : const char *dlid, *name;
234 : : int r;
235 : :
236 [ # # ]: 0 : if (!(name = build_dm_name(mem, lv->vg->name, lv->name, NULL))) {
237 : 0 : log_error("name build failed for %s", lv->name);
238 : 0 : return 0;
239 : : }
240 : :
241 [ # # ]: 0 : if (!(dlid = _build_dlid(mem, lv->lvid.s, NULL))) {
242 : 0 : log_error("dlid build failed for %s", lv->name);
243 : 0 : return 0;
244 : : }
245 : :
246 : 0 : log_debug("Getting device info for %s [%s]", name, dlid);
247 : 0 : r = _info(dlid, with_open_count, with_read_ahead, info, read_ahead);
248 : :
249 : 0 : dm_pool_free(mem, (char*)name);
250 : 0 : return r;
251 : : }
252 : :
253 : 0 : static const struct dm_info *_cached_info(struct dm_pool *mem,
254 : : const struct logical_volume *lv,
255 : : struct dm_tree *dtree)
256 : : {
257 : : const char *dlid;
258 : : struct dm_tree_node *dnode;
259 : : const struct dm_info *dinfo;
260 : :
261 [ # # ]: 0 : if (!(dlid = _build_dlid(mem, lv->lvid.s, NULL))) {
262 : 0 : log_error("dlid build failed for %s", lv->name);
263 : 0 : return NULL;
264 : : }
265 : :
266 : : /* An activating merging origin won't have a node in the tree yet */
267 [ # # ]: 0 : if (!(dnode = dm_tree_find_node_by_uuid(dtree, dlid)))
268 : 0 : return NULL;
269 : :
270 [ # # ]: 0 : if (!(dinfo = dm_tree_node_get_info(dnode))) {
271 : 0 : log_error("failed to get info from tree node for %s", lv->name);
272 : 0 : return NULL;
273 : : }
274 : :
275 [ # # ]: 0 : if (!dinfo->exists)
276 : 0 : return NULL;
277 : :
278 : 0 : return dinfo;
279 : : }
280 : :
281 : : /* FIXME Interface must cope with multiple targets */
282 : 0 : static int _status_run(const char *name, const char *uuid,
283 : : unsigned long long *s, unsigned long long *l,
284 : : char **t, uint32_t t_size, char **p, uint32_t p_size)
285 : : {
286 : 0 : int r = 0;
287 : : struct dm_task *dmt;
288 : : struct dm_info info;
289 : 0 : void *next = NULL;
290 : : uint64_t start, length;
291 : 0 : char *type = NULL;
292 : 0 : char *params = NULL;
293 : :
294 [ # # ]: 0 : if (!(dmt = _setup_task(name, uuid, 0, DM_DEVICE_STATUS, 0, 0)))
295 : 0 : return_0;
296 : :
297 [ # # ]: 0 : if (!dm_task_no_open_count(dmt))
298 : 0 : log_error("Failed to disable open_count");
299 : :
300 [ # # ]: 0 : if (!dm_task_run(dmt))
301 : 0 : goto_out;
302 : :
303 [ # # ][ # # ]: 0 : if (!dm_task_get_info(dmt, &info) || !info.exists)
304 : 0 : goto_out;
305 : :
306 : : do {
307 : 0 : next = dm_get_next_target(dmt, next, &start, &length,
308 : : &type, ¶ms);
309 [ # # ]: 0 : if (type) {
310 : 0 : *s = start;
311 : 0 : *l = length;
312 : : /* Make sure things are null terminated */
313 : 0 : strncpy(*t, type, t_size);
314 : 0 : (*t)[t_size - 1] = '\0';
315 : 0 : strncpy(*p, params, p_size);
316 : 0 : (*p)[p_size - 1] = '\0';
317 : :
318 : 0 : r = 1;
319 : : /* FIXME Cope with multiple targets! */
320 : 0 : break;
321 : : }
322 : :
323 [ # # ]: 0 : } while (next);
324 : :
325 : : out:
326 : 0 : dm_task_destroy(dmt);
327 : 0 : return r;
328 : : }
329 : :
330 : : static int _status(const char *name, const char *uuid,
331 : : unsigned long long *start, unsigned long long *length,
332 : : char **type, uint32_t type_size, char **params,
333 : : uint32_t param_size) __attribute__ ((unused));
334 : :
335 : 0 : static int _status(const char *name, const char *uuid,
336 : : unsigned long long *start, unsigned long long *length,
337 : : char **type, uint32_t type_size, char **params,
338 : : uint32_t param_size)
339 : : {
340 [ # # ][ # # ]: 0 : if (uuid && *uuid) {
341 [ # # # # ]: 0 : if (_status_run(NULL, uuid, start, length, type,
342 : 0 : type_size, params, param_size) &&
343 : 0 : *params)
344 : 0 : return 1;
345 [ # # # # ]: 0 : else if (_status_run(NULL, uuid + sizeof(UUID_PREFIX) - 1, start,
346 : : length, type, type_size, params,
347 : 0 : param_size) &&
348 : 0 : *params)
349 : 0 : return 1;
350 : : }
351 : :
352 [ # # # # ]: 0 : if (name && _status_run(name, NULL, start, length, type, type_size,
353 : 0 : params, param_size))
354 : 0 : return 1;
355 : :
356 : 0 : return 0;
357 : : }
358 : :
359 : 0 : static int _lv_has_target_type(struct dev_manager *dm,
360 : : struct logical_volume *lv,
361 : : const char *layer,
362 : : const char *target_type)
363 : : {
364 : 0 : int r = 0;
365 : : char *dlid;
366 : : struct dm_task *dmt;
367 : : struct dm_info info;
368 : 0 : void *next = NULL;
369 : : uint64_t start, length;
370 : 0 : char *type = NULL;
371 : 0 : char *params = NULL;
372 : :
373 [ # # ]: 0 : if (!(dlid = build_dlid(dm, lv->lvid.s, layer)))
374 : 0 : return_0;
375 : :
376 [ # # ]: 0 : if (!(dmt = _setup_task(NULL, dlid, 0,
377 : : DM_DEVICE_STATUS, 0, 0)))
378 : 0 : return_0;
379 : :
380 [ # # ]: 0 : if (!dm_task_no_open_count(dmt))
381 : 0 : log_error("Failed to disable open_count");
382 : :
383 [ # # ]: 0 : if (!dm_task_run(dmt))
384 : 0 : goto_out;
385 : :
386 [ # # ][ # # ]: 0 : if (!dm_task_get_info(dmt, &info) || !info.exists)
387 : 0 : goto_out;
388 : :
389 : : do {
390 : 0 : next = dm_get_next_target(dmt, next, &start, &length,
391 : : &type, ¶ms);
392 [ # # # # ]: 0 : if (type && strncmp(type, target_type,
393 : 0 : strlen(target_type)) == 0) {
394 [ # # ]: 0 : if (info.live_table)
395 : 0 : r = 1;
396 : 0 : break;
397 : : }
398 [ # # ]: 0 : } while (next);
399 : :
400 : : out:
401 : 0 : dm_task_destroy(dmt);
402 : 0 : return r;
403 : : }
404 : :
405 : 0 : static percent_range_t _combine_percent_ranges(percent_range_t a,
406 : : percent_range_t b)
407 : : {
408 [ # # ][ # # ]: 0 : if (a == PERCENT_INVALID || b == PERCENT_INVALID)
409 : 0 : return PERCENT_INVALID;
410 : :
411 [ # # ][ # # ]: 0 : if (a == PERCENT_100 && b == PERCENT_100)
412 : 0 : return PERCENT_100;
413 : :
414 [ # # ][ # # ]: 0 : if (a == PERCENT_0 && b == PERCENT_0)
415 : 0 : return PERCENT_0;
416 : :
417 : 0 : return PERCENT_0_TO_100;
418 : : }
419 : :
420 : 0 : static int _percent_run(struct dev_manager *dm, const char *name,
421 : : const char *dlid,
422 : : const char *target_type, int wait,
423 : : const struct logical_volume *lv, float *percent,
424 : : percent_range_t *overall_percent_range,
425 : : uint32_t *event_nr, int fail_if_percent_unsupported)
426 : : {
427 : 0 : int r = 0;
428 : : struct dm_task *dmt;
429 : : struct dm_info info;
430 : 0 : void *next = NULL;
431 : : uint64_t start, length;
432 : 0 : char *type = NULL;
433 : 0 : char *params = NULL;
434 : 0 : const struct dm_list *segh = &lv->segments;
435 : 0 : struct lv_segment *seg = NULL;
436 : : struct segment_type *segtype;
437 : 0 : percent_range_t percent_range = 0, combined_percent_range = 0;
438 : 0 : int first_time = 1;
439 : :
440 : 0 : uint64_t total_numerator = 0, total_denominator = 0;
441 : :
442 : 0 : *percent = -1;
443 : 0 : *overall_percent_range = PERCENT_INVALID;
444 : :
445 [ # # ][ # # ]: 0 : if (!(dmt = _setup_task(name, dlid, event_nr,
446 : : wait ? DM_DEVICE_WAITEVENT : DM_DEVICE_STATUS, 0, 0)))
447 : 0 : return_0;
448 : :
449 [ # # ]: 0 : if (!dm_task_no_open_count(dmt))
450 : 0 : log_error("Failed to disable open_count");
451 : :
452 [ # # ]: 0 : if (!dm_task_run(dmt))
453 : 0 : goto_out;
454 : :
455 [ # # ][ # # ]: 0 : if (!dm_task_get_info(dmt, &info) || !info.exists)
456 : 0 : goto_out;
457 : :
458 [ # # ]: 0 : if (event_nr)
459 : 0 : *event_nr = info.event_nr;
460 : :
461 : : do {
462 : 0 : next = dm_get_next_target(dmt, next, &start, &length, &type,
463 : : ¶ms);
464 [ # # ]: 0 : if (lv) {
465 [ # # ]: 0 : if (!(segh = dm_list_next(&lv->segments, segh))) {
466 : 0 : log_error("Number of segments in active LV %s "
467 : : "does not match metadata", lv->name);
468 : 0 : goto out;
469 : : }
470 : 0 : seg = dm_list_item(segh, struct lv_segment);
471 : : }
472 : :
473 [ # # ][ # # ]: 0 : if (!type || !params)
474 : 0 : continue;
475 : :
476 [ # # ]: 0 : if (!(segtype = get_segtype_from_string(dm->cmd, target_type)))
477 : 0 : continue;
478 : :
479 [ # # ]: 0 : if (strcmp(type, target_type)) {
480 : : /* If kernel's type isn't an exact match is it compatible? */
481 [ # # # # ]: 0 : if (!segtype->ops->target_status_compatible ||
482 : 0 : !segtype->ops->target_status_compatible(type))
483 : 0 : continue;
484 : : }
485 : :
486 [ # # # # ]: 0 : if (segtype->ops->target_percent &&
487 : 0 : !segtype->ops->target_percent(&dm->target_state,
488 : : &percent_range, dm->mem,
489 : : dm->cmd, seg, params,
490 : : &total_numerator,
491 : : &total_denominator))
492 : 0 : goto_out;
493 : :
494 [ # # ]: 0 : if (first_time) {
495 : 0 : combined_percent_range = percent_range;
496 : 0 : first_time = 0;
497 : : } else
498 : 0 : combined_percent_range =
499 : 0 : _combine_percent_ranges(combined_percent_range,
500 : : percent_range);
501 [ # # ]: 0 : } while (next);
502 : :
503 [ # # ][ # # ]: 0 : if (lv && (segh = dm_list_next(&lv->segments, segh))) {
504 : 0 : log_error("Number of segments in active LV %s does not "
505 : : "match metadata", lv->name);
506 : 0 : goto out;
507 : : }
508 : :
509 [ # # ]: 0 : if (total_denominator) {
510 : 0 : *percent = (float) total_numerator *100 / total_denominator;
511 : 0 : *overall_percent_range = combined_percent_range;
512 : : } else {
513 : 0 : *percent = 100;
514 [ # # ]: 0 : if (first_time) {
515 : : /* above ->target_percent() was not executed! */
516 : : /* FIXME why return PERCENT_100 et. al. in this case? */
517 : 0 : *overall_percent_range = PERCENT_100;
518 [ # # ]: 0 : if (fail_if_percent_unsupported)
519 : 0 : goto_out;
520 : : } else
521 : 0 : *overall_percent_range = combined_percent_range;
522 : : }
523 : :
524 : 0 : log_debug("LV percent: %f", *percent);
525 : 0 : r = 1;
526 : :
527 : : out:
528 : 0 : dm_task_destroy(dmt);
529 : 0 : return r;
530 : : }
531 : :
532 : 0 : static int _percent(struct dev_manager *dm, const char *name, const char *dlid,
533 : : const char *target_type, int wait,
534 : : const struct logical_volume *lv, float *percent,
535 : : percent_range_t *overall_percent_range, uint32_t *event_nr,
536 : : int fail_if_percent_unsupported)
537 : : {
538 [ # # ][ # # ]: 0 : if (dlid && *dlid) {
539 [ # # ]: 0 : if (_percent_run(dm, NULL, dlid, target_type, wait, lv, percent,
540 : : overall_percent_range, event_nr,
541 : : fail_if_percent_unsupported))
542 : 0 : return 1;
543 [ # # ]: 0 : else if (_percent_run(dm, NULL, dlid + sizeof(UUID_PREFIX) - 1,
544 : : target_type, wait, lv, percent,
545 : : overall_percent_range, event_nr,
546 : : fail_if_percent_unsupported))
547 : 0 : return 1;
548 : : }
549 : :
550 [ # # # # ]: 0 : if (name && _percent_run(dm, name, NULL, target_type, wait, lv, percent,
551 : : overall_percent_range, event_nr,
552 : 0 : fail_if_percent_unsupported))
553 : 0 : return 1;
554 : :
555 : 0 : return 0;
556 : : }
557 : :
558 : : /*
559 : : * dev_manager implementation.
560 : : */
561 : 0 : struct dev_manager *dev_manager_create(struct cmd_context *cmd,
562 : : const char *vg_name)
563 : : {
564 : : struct dm_pool *mem;
565 : : struct dev_manager *dm;
566 : :
567 [ # # ]: 0 : if (!(mem = dm_pool_create("dev_manager", 16 * 1024)))
568 : 0 : return_NULL;
569 : :
570 [ # # ]: 0 : if (!(dm = dm_pool_zalloc(mem, sizeof(*dm))))
571 : 0 : goto_bad;
572 : :
573 : 0 : dm->cmd = cmd;
574 : 0 : dm->mem = mem;
575 : :
576 [ # # ]: 0 : if (!(dm->vg_name = dm_pool_strdup(dm->mem, vg_name)))
577 : 0 : goto_bad;
578 : :
579 : 0 : dm->target_state = NULL;
580 : :
581 : 0 : dm_udev_set_sync_support(cmd->current_settings.udev_sync);
582 : :
583 : 0 : return dm;
584 : :
585 : : bad:
586 : 0 : dm_pool_destroy(mem);
587 : 0 : return NULL;
588 : : }
589 : :
590 : 0 : void dev_manager_destroy(struct dev_manager *dm)
591 : : {
592 : 0 : dm_pool_destroy(dm->mem);
593 : 0 : }
594 : :
595 : 2 : void dev_manager_release(void)
596 : : {
597 : 2 : dm_lib_release();
598 : 2 : }
599 : :
600 : 1 : void dev_manager_exit(void)
601 : : {
602 : 1 : dm_lib_exit();
603 : 1 : }
604 : :
605 : 0 : int dev_manager_snapshot_percent(struct dev_manager *dm,
606 : : const struct logical_volume *lv,
607 : : float *percent, percent_range_t *percent_range)
608 : : {
609 : : char *name;
610 : : const char *dlid;
611 : 0 : int fail_if_percent_unsupported = 0;
612 : :
613 [ # # ]: 0 : if (lv_is_merging_origin(lv)) {
614 : : /*
615 : : * Set 'fail_if_percent_unsupported', otherwise passing
616 : : * unsupported LV types to _percent will lead to a default
617 : : * successful return with percent_range as PERCENT_100.
618 : : * - For a merging origin, this will result in a polldaemon
619 : : * that runs infinitely (because completion is PERCENT_0)
620 : : * - We unfortunately don't yet _know_ if a snapshot-merge
621 : : * target is active (activation is deferred if dev is open);
622 : : * so we can't short-circuit origin devices based purely on
623 : : * existing LVM LV attributes.
624 : : */
625 : 0 : fail_if_percent_unsupported = 1;
626 : : }
627 : :
628 : : /*
629 : : * Build a name for the top layer.
630 : : */
631 [ # # ]: 0 : if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, NULL)))
632 : 0 : return_0;
633 : :
634 [ # # ]: 0 : if (!(dlid = build_dlid(dm, lv->lvid.s, NULL)))
635 : 0 : return_0;
636 : :
637 : : /*
638 : : * Try and get some info on this device.
639 : : */
640 : 0 : log_debug("Getting device status percentage for %s", name);
641 [ # # ]: 0 : if (!(_percent(dm, name, dlid, "snapshot", 0, NULL, percent,
642 : : percent_range, NULL, fail_if_percent_unsupported)))
643 : 0 : return_0;
644 : :
645 : : /* FIXME dm_pool_free ? */
646 : :
647 : : /* If the snapshot isn't available, percent will be -1 */
648 : 0 : return 1;
649 : : }
650 : :
651 : : /* FIXME Merge with snapshot_percent, auto-detecting target type */
652 : : /* FIXME Cope with more than one target */
653 : 0 : int dev_manager_mirror_percent(struct dev_manager *dm,
654 : : const struct logical_volume *lv, int wait,
655 : : float *percent, percent_range_t *percent_range,
656 : : uint32_t *event_nr)
657 : : {
658 : : char *name;
659 : : const char *dlid;
660 [ # # ]: 0 : const char *suffix = (lv_is_origin(lv)) ? "real" : NULL;
661 : :
662 : : /*
663 : : * Build a name for the top layer.
664 : : */
665 [ # # ]: 0 : if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, suffix)))
666 : 0 : return_0;
667 : :
668 : : /* FIXME dm_pool_free ? */
669 : :
670 [ # # ]: 0 : if (!(dlid = build_dlid(dm, lv->lvid.s, suffix))) {
671 : 0 : log_error("dlid build failed for %s", lv->name);
672 : 0 : return 0;
673 : : }
674 : :
675 : 0 : log_debug("Getting device mirror status percentage for %s", name);
676 [ # # ]: 0 : if (!(_percent(dm, name, dlid, "mirror", wait, lv, percent,
677 : : percent_range, event_nr, 0)))
678 : 0 : return_0;
679 : :
680 : 0 : return 1;
681 : : }
682 : :
683 : : #if 0
684 : : log_very_verbose("%s %s", sus ? "Suspending" : "Resuming", name);
685 : :
686 : : log_verbose("Loading %s", dl->name);
687 : : log_very_verbose("Activating %s read-only", dl->name);
688 : : log_very_verbose("Activated %s %s %03u:%03u", dl->name,
689 : : dl->dlid, dl->info.major, dl->info.minor);
690 : :
691 : : if (_get_flag(dl, VISIBLE))
692 : : log_verbose("Removing %s", dl->name);
693 : : else
694 : : log_very_verbose("Removing %s", dl->name);
695 : :
696 : : log_debug("Adding target: %" PRIu64 " %" PRIu64 " %s %s",
697 : : extent_size * seg->le, extent_size * seg->len, target, params);
698 : :
699 : : log_debug("Adding target: 0 %" PRIu64 " snapshot-origin %s",
700 : : dl->lv->size, params);
701 : : log_debug("Adding target: 0 %" PRIu64 " snapshot %s", size, params);
702 : : log_debug("Getting device info for %s", dl->name);
703 : :
704 : : /* Rename? */
705 : : if ((suffix = strrchr(dl->dlid + sizeof(UUID_PREFIX) - 1, '-')))
706 : : suffix++;
707 : : new_name = build_dm_name(dm->mem, dm->vg_name, dl->lv->name,
708 : : suffix);
709 : :
710 : : static int _belong_to_vg(const char *vgname, const char *name)
711 : : {
712 : : const char *v = vgname, *n = name;
713 : :
714 : : while (*v) {
715 : : if ((*v != *n) || (*v == '-' && *(++n) != '-'))
716 : : return 0;
717 : : v++, n++;
718 : : }
719 : :
720 : : if (*n == '-' && *(n + 1) != '-')
721 : : return 1;
722 : : else
723 : : return 0;
724 : : }
725 : :
726 : : if (!(snap_seg = find_cow(lv)))
727 : : return 1;
728 : :
729 : : old_origin = snap_seg->origin;
730 : :
731 : : /* Was this the last active snapshot with this origin? */
732 : : dm_list_iterate_items(lvl, active_head) {
733 : : active = lvl->lv;
734 : : if ((snap_seg = find_cow(active)) &&
735 : : snap_seg->origin == old_origin) {
736 : : return 1;
737 : : }
738 : : }
739 : :
740 : : #endif
741 : :
742 : : /*************************/
743 : : /* NEW CODE STARTS HERE */
744 : : /*************************/
745 : :
746 : 0 : static int _dev_manager_lv_mknodes(const struct logical_volume *lv)
747 : : {
748 : : char *name;
749 : :
750 [ # # ]: 0 : if (!(name = build_dm_name(lv->vg->cmd->mem, lv->vg->name,
751 : 0 : lv->name, NULL)))
752 : 0 : return_0;
753 : :
754 : 0 : return fs_add_lv(lv, name);
755 : : }
756 : :
757 : 0 : static int _dev_manager_lv_rmnodes(const struct logical_volume *lv)
758 : : {
759 : 0 : return fs_del_lv(lv);
760 : : }
761 : :
762 : 0 : int dev_manager_mknodes(const struct logical_volume *lv)
763 : : {
764 : : struct dm_info dminfo;
765 : : const char *name;
766 : 0 : int r = 0;
767 : :
768 [ # # ]: 0 : if (!(name = build_dm_name(lv->vg->cmd->mem, lv->vg->name, lv->name, NULL)))
769 : 0 : return_0;
770 : :
771 [ # # ]: 0 : if ((r = _info_run(name, NULL, &dminfo, NULL, 1, 0, 0, 0, 0))) {
772 [ # # ]: 0 : if (dminfo.exists) {
773 [ # # ]: 0 : if (lv_is_visible(lv))
774 : 0 : r = _dev_manager_lv_mknodes(lv);
775 : : } else
776 : 0 : r = _dev_manager_lv_rmnodes(lv);
777 : : }
778 : :
779 : 0 : dm_pool_free(lv->vg->cmd->mem, (char*)name);
780 : 0 : return r;
781 : : }
782 : :
783 : 0 : static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
784 : : struct logical_volume *lv, const char *layer)
785 : : {
786 : : char *dlid, *name;
787 : : struct dm_info info, info2;
788 : 0 : uint16_t udev_flags = 0;
789 : :
790 [ # # ]: 0 : if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
791 : 0 : return_0;
792 : :
793 [ # # ]: 0 : if (!(dlid = build_dlid(dm, lv->lvid.s, layer)))
794 : 0 : return_0;
795 : :
796 : 0 : log_debug("Getting device info for %s [%s]", name, dlid);
797 [ # # ]: 0 : if (!_info(dlid, 1, 0, &info, NULL)) {
798 : 0 : log_error("Failed to get info for %s [%s].", name, dlid);
799 : 0 : return 0;
800 : : }
801 : :
802 : : /*
803 : : * For top level volumes verify that existing device match
804 : : * requested major/minor and that major/minor pair is available for use
805 : : */
806 [ # # ][ # # ]: 0 : if (!layer && lv->major != -1 && lv->minor != -1) {
[ # # ]
807 : : /*
808 : : * FIXME compare info.major with lv->major if multiple major support
809 : : */
810 [ # # ][ # # ]: 0 : if (info.exists && (info.minor != lv->minor)) {
811 : 0 : log_error("Volume %s (%" PRIu32 ":%" PRIu32")"
812 : : " differs from already active device "
813 : : "(%" PRIu32 ":%" PRIu32")",
814 : : lv->name, lv->major, lv->minor, info.major, info.minor);
815 : 0 : return 0;
816 : : }
817 [ # # ][ # # ]: 0 : if (!info.exists && _info_by_dev(lv->major, lv->minor, &info2) &&
[ # # ]
818 : 0 : info2.exists) {
819 : 0 : log_error("The requested major:minor pair "
820 : : "(%" PRIu32 ":%" PRIu32") is already used",
821 : : lv->major, lv->minor);
822 : 0 : return 0;
823 : : }
824 : : }
825 : :
826 [ # # ][ # # ]: 0 : if (layer || !lv_is_visible(lv))
827 : 0 : udev_flags |= DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG |
828 : : DM_UDEV_DISABLE_DISK_RULES_FLAG |
829 : : DM_UDEV_DISABLE_OTHER_RULES_FLAG;
830 : :
831 [ # # ]: 0 : if (lv_is_cow(lv))
832 : 0 : udev_flags |= DM_UDEV_LOW_PRIORITY_FLAG;
833 : :
834 [ # # ]: 0 : if (!dm->cmd->current_settings.udev_rules)
835 : 0 : udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG |
836 : : DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG;
837 : :
838 [ # # ][ # # ]: 0 : if (info.exists && !dm_tree_add_dev_with_udev_flags(dtree, info.major,
839 : : info.minor, udev_flags)) {
840 : 0 : log_error("Failed to add device (%" PRIu32 ":%" PRIu32") to dtree",
841 : : info.major, info.minor);
842 : 0 : return 0;
843 : : }
844 : :
845 : 0 : return 1;
846 : : }
847 : :
848 : : /*
849 : : * Add LV and any known dependencies
850 : : */
851 : 0 : static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, struct logical_volume *lv)
852 : : {
853 : 0 : log_very_verbose("Add partial dtree: %s", lv->name);
854 : :
855 [ # # ]: 0 : if (!_add_dev_to_dtree(dm, dtree, lv, NULL))
856 : 0 : return_0;
857 : :
858 : : /* FIXME Can we avoid doing this every time? */
859 [ # # ]: 0 : if (!_add_dev_to_dtree(dm, dtree, lv, "real"))
860 : 0 : return_0;
861 : :
862 [ # # ]: 0 : if (!_add_dev_to_dtree(dm, dtree, lv, "cow"))
863 : 0 : return_0;
864 : :
865 [ # # ]: 0 : if ((lv->status & MIRRORED) && first_seg(lv)->log_lv &&
[ # # # # ]
866 : 0 : !_add_dev_to_dtree(dm, dtree, first_seg(lv)->log_lv, NULL))
867 : 0 : return_0;
868 : :
869 : 0 : return 1;
870 : : }
871 : :
872 : : /*
873 : : * Add devices from replicator
874 : : * use _add_dev_to_dtree() directly instead of _add_lv_to_dtree()
875 : : * no need to extend its check with _slog, _rlog, _rimage
876 : : */
877 : 0 : static int _create_partial_replicator(struct dev_manager *dm,
878 : : struct dm_tree *dtree,
879 : : struct lv_segment *seg)
880 : : {
881 : : struct replicator_device *rdev;
882 : : struct replicator_site *rsite;
883 : : const char *replicator_dlid;
884 : :
885 [ # # ]: 0 : if (!lv_is_active_replicator_dev(seg->lv)) {
886 [ # # ]: 0 : if (!_add_dev_to_dtree(dm, dtree, seg->lv->rdevice->lv,
887 : : NULL))
888 : 0 : return_0;
889 : 0 : return 1;
890 : : }
891 : :
892 : : /* Add all related devs for replicator */
893 [ # # ]: 0 : dm_list_iterate_items(rsite, &seg->replicator->rsites) {
894 [ # # ]: 0 : dm_list_iterate_items(rdev, &rsite->rdevices) {
895 [ # # ]: 0 : if (rsite->state == REPLICATOR_STATE_ACTIVE) {
896 : : /* Add _rimage LV */
897 [ # # # # ]: 0 : if (rdev->lv &&
898 : 0 : !_add_dev_to_dtree(dm, dtree,
899 : : rdev->lv, NULL))
900 : 0 : return_0;
901 : :
902 : : /* Add replicator-dev LV */
903 [ # # # # ]: 0 : if (seg->lv != rdev->replicator_dev->lv &&
904 : 0 : !_add_dev_to_dtree(dm, dtree,
905 : 0 : rdev->replicator_dev->lv,
906 : : NULL))
907 : 0 : return_0;
908 : : }
909 : :
910 [ # # ]: 0 : if (!rdev->rsite->vg_name)
911 : 0 : continue;
912 : :
913 [ # # # # ]: 0 : if (rdev->lv &&
914 : 0 : !_add_dev_to_dtree(dm, dtree, rdev->lv, NULL))
915 : 0 : return_0;
916 : :
917 [ # # # # ]: 0 : if (rdev->slog &&
918 : 0 : !_add_dev_to_dtree(dm, dtree, rdev->slog, NULL))
919 : 0 : return_0;
920 : :
921 : : }
922 : : }
923 : :
924 : : /* Add rlog and replicator devices */
925 [ # # # # ]: 0 : if (first_seg(seg->replicator)->rlog_lv &&
926 : 0 : !_add_dev_to_dtree(dm, dtree,
927 : 0 : first_seg(seg->replicator)->rlog_lv, NULL))
928 : 0 : return_0;
929 [ # # ]: 0 : if (!_add_dev_to_dtree(dm, dtree, seg->replicator, NULL))
930 : 0 : return_0;
931 : :
932 : : /* Set suspend priority for replicator device */
933 [ # # ]: 0 : if (!(replicator_dlid = build_dlid(dm, seg->replicator->lvid.s, NULL)))
934 : 0 : return_0;
935 [ # # ]: 0 : if (!dm_tree_set_suspend_priority(dtree, replicator_dlid, 1))
936 : 0 : return_0;
937 : :
938 : 0 : return 1;
939 : : }
940 : :
941 : 0 : static struct dm_tree *_create_partial_dtree(struct dev_manager *dm, struct logical_volume *lv)
942 : : {
943 : : struct dm_tree *dtree;
944 : : struct dm_list *snh, *snht;
945 : : struct lv_segment *seg;
946 : : uint32_t s;
947 : :
948 [ # # ]: 0 : if (!(dtree = dm_tree_create())) {
949 : 0 : log_error("Partial dtree creation failed for %s.", lv->name);
950 : 0 : return NULL;
951 : : }
952 : :
953 [ # # ]: 0 : if (!_add_lv_to_dtree(dm, dtree, lv))
954 : 0 : goto_bad;
955 : :
956 : : /* Add any snapshots of this LV */
957 [ # # ]: 0 : dm_list_iterate_safe(snh, snht, &lv->snapshot_segs)
958 [ # # ]: 0 : if (!_add_lv_to_dtree(dm, dtree, dm_list_struct_base(snh, struct lv_segment, origin_list)->cow))
959 : 0 : goto_bad;
960 : :
961 : : /* Add any replicator-dev LVs of this LV */
962 [ # # ]: 0 : dm_list_iterate_items(seg, &lv->segments)
963 [ # # # # ]: 0 : if (seg_is_replicator_dev(seg) &&
964 : 0 : !_create_partial_replicator(dm, dtree, seg))
965 : 0 : goto_bad;
966 : :
967 : : /* Add any LVs used by segments in this LV */
968 [ # # ]: 0 : dm_list_iterate_items(seg, &lv->segments)
969 [ # # ]: 0 : for (s = 0; s < seg->area_count; s++)
970 [ # # ][ # # ]: 0 : if (seg_type(seg, s) == AREA_LV && seg_lv(seg, s)) {
971 [ # # ]: 0 : if (!_add_lv_to_dtree(dm, dtree, seg_lv(seg, s)))
972 : 0 : goto_bad;
973 : : }
974 : :
975 : 0 : return dtree;
976 : :
977 : : bad:
978 : 0 : dm_tree_free(dtree);
979 : 0 : return NULL;
980 : : }
981 : :
982 : 0 : static char *_add_error_device(struct dev_manager *dm, struct dm_tree *dtree,
983 : : struct lv_segment *seg, int s)
984 : : {
985 : : char *id, *name;
986 : : char errid[32];
987 : : struct dm_tree_node *node;
988 : : struct lv_segment *seg_i;
989 : 0 : int segno = -1, i = 0;;
990 : 0 : uint64_t size = seg->len * seg->lv->vg->extent_size;
991 : :
992 [ # # ]: 0 : dm_list_iterate_items(seg_i, &seg->lv->segments) {
993 [ # # ]: 0 : if (seg == seg_i)
994 : 0 : segno = i;
995 : 0 : ++i;
996 : : }
997 : :
998 [ # # ]: 0 : if (segno < 0) {
999 : 0 : log_error("_add_error_device called with bad segment");
1000 : 0 : return_NULL;
1001 : : }
1002 : :
1003 : 0 : sprintf(errid, "missing_%d_%d", segno, s);
1004 : :
1005 [ # # ]: 0 : if (!(id = build_dlid(dm, seg->lv->lvid.s, errid)))
1006 : 0 : return_NULL;
1007 : :
1008 [ # # ]: 0 : if (!(name = build_dm_name(dm->mem, seg->lv->vg->name,
1009 : 0 : seg->lv->name, errid)))
1010 : 0 : return_NULL;
1011 [ # # ]: 0 : if (!(node = dm_tree_add_new_dev(dtree, name, id, 0, 0, 0, 0, 0)))
1012 : 0 : return_NULL;
1013 [ # # ]: 0 : if (!dm_tree_node_add_error_target(node, size))
1014 : 0 : return_NULL;
1015 : :
1016 : 0 : return id;
1017 : : }
1018 : :
1019 : 0 : static int _add_error_area(struct dev_manager *dm, struct dm_tree_node *node,
1020 : : struct lv_segment *seg, int s)
1021 : : {
1022 : : char *dlid;
1023 : 0 : uint64_t extent_size = seg->lv->vg->extent_size;
1024 : :
1025 [ # # ]: 0 : if (!strcmp(dm->cmd->stripe_filler, "error")) {
1026 : : /*
1027 : : * FIXME, the tree pointer is first field of dm_tree_node, but
1028 : : * we don't have the struct definition available.
1029 : : */
1030 : 0 : struct dm_tree **tree = (struct dm_tree **) node;
1031 : 0 : dlid = _add_error_device(dm, *tree, seg, s);
1032 [ # # ]: 0 : if (!dlid)
1033 : 0 : return_0;
1034 : 0 : dm_tree_node_add_target_area(node, NULL, dlid,
1035 : 0 : extent_size * seg_le(seg, s));
1036 : : } else
1037 : 0 : dm_tree_node_add_target_area(node,
1038 : 0 : dm->cmd->stripe_filler,
1039 : : NULL, UINT64_C(0));
1040 : :
1041 : 0 : return 1;
1042 : : }
1043 : :
1044 : 0 : int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
1045 : : struct dm_tree_node *node, uint32_t start_area,
1046 : : uint32_t areas)
1047 : : {
1048 : 0 : uint64_t extent_size = seg->lv->vg->extent_size;
1049 : : uint32_t s;
1050 : : char *dlid;
1051 : :
1052 [ # # ]: 0 : for (s = start_area; s < areas; s++) {
1053 [ # # ][ # # ]: 0 : if ((seg_type(seg, s) == AREA_PV &&
[ # # ][ # # ]
[ # # ][ # # ]
1054 : 0 : (!seg_pvseg(seg, s) ||
1055 : 0 : !seg_pv(seg, s) ||
1056 : 0 : !seg_dev(seg, s))) ||
1057 : 0 : (seg_type(seg, s) == AREA_LV && !seg_lv(seg, s))) {
1058 [ # # ]: 0 : if (!_add_error_area(dm, node, seg, s))
1059 : 0 : return_0;
1060 [ # # ]: 0 : } else if (seg_type(seg, s) == AREA_PV)
1061 : 0 : dm_tree_node_add_target_area(node,
1062 : 0 : dev_name(seg_dev(seg, s)),
1063 : : NULL,
1064 : 0 : (seg_pv(seg, s)->pe_start +
1065 : 0 : (extent_size * seg_pe(seg, s))));
1066 [ # # ]: 0 : else if (seg_type(seg, s) == AREA_LV) {
1067 [ # # ]: 0 : if (!(dlid = build_dlid(dm,
1068 : 0 : seg_lv(seg, s)->lvid.s,
1069 : : NULL)))
1070 : 0 : return_0;
1071 : 0 : dm_tree_node_add_target_area(node, NULL, dlid,
1072 : 0 : extent_size * seg_le(seg, s));
1073 : : } else {
1074 : 0 : log_error(INTERNAL_ERROR "Unassigned area found in LV %s.",
1075 : : seg->lv->name);
1076 : 0 : return 0;
1077 : : }
1078 : : }
1079 : :
1080 : 0 : return 1;
1081 : : }
1082 : :
1083 : 0 : static int _add_origin_target_to_dtree(struct dev_manager *dm,
1084 : : struct dm_tree_node *dnode,
1085 : : struct logical_volume *lv)
1086 : : {
1087 : : const char *real_dlid;
1088 : :
1089 [ # # ]: 0 : if (!(real_dlid = build_dlid(dm, lv->lvid.s, "real")))
1090 : 0 : return_0;
1091 : :
1092 [ # # ]: 0 : if (!dm_tree_node_add_snapshot_origin_target(dnode, lv->size, real_dlid))
1093 : 0 : return_0;
1094 : :
1095 : 0 : return 1;
1096 : : }
1097 : :
1098 : 0 : static int _add_snapshot_merge_target_to_dtree(struct dev_manager *dm,
1099 : : struct dm_tree_node *dnode,
1100 : : struct logical_volume *lv)
1101 : : {
1102 : : const char *origin_dlid, *cow_dlid, *merge_dlid;
1103 : 0 : struct lv_segment *merging_cow_seg = find_merging_cow(lv);
1104 : :
1105 [ # # ]: 0 : if (!(origin_dlid = build_dlid(dm, lv->lvid.s, "real")))
1106 : 0 : return_0;
1107 : :
1108 [ # # ]: 0 : if (!(cow_dlid = build_dlid(dm, merging_cow_seg->cow->lvid.s, "cow")))
1109 : 0 : return_0;
1110 : :
1111 [ # # ]: 0 : if (!(merge_dlid = build_dlid(dm, merging_cow_seg->cow->lvid.s, NULL)))
1112 : 0 : return_0;
1113 : :
1114 [ # # ]: 0 : if (!dm_tree_node_add_snapshot_merge_target(dnode, lv->size, origin_dlid,
1115 : : cow_dlid, merge_dlid,
1116 : : merging_cow_seg->chunk_size))
1117 : 0 : return_0;
1118 : :
1119 : 0 : return 1;
1120 : : }
1121 : :
1122 : 0 : static int _add_snapshot_target_to_dtree(struct dev_manager *dm,
1123 : : struct dm_tree_node *dnode,
1124 : : struct logical_volume *lv)
1125 : : {
1126 : : const char *origin_dlid;
1127 : : const char *cow_dlid;
1128 : : struct lv_segment *snap_seg;
1129 : : uint64_t size;
1130 : :
1131 [ # # ]: 0 : if (!(snap_seg = find_cow(lv))) {
1132 : 0 : log_error("Couldn't find snapshot for '%s'.", lv->name);
1133 : 0 : return 0;
1134 : : }
1135 : :
1136 [ # # ]: 0 : if (!(origin_dlid = build_dlid(dm, snap_seg->origin->lvid.s, "real")))
1137 : 0 : return_0;
1138 : :
1139 [ # # ]: 0 : if (!(cow_dlid = build_dlid(dm, snap_seg->cow->lvid.s, "cow")))
1140 : 0 : return_0;
1141 : :
1142 : 0 : size = (uint64_t) snap_seg->len * snap_seg->origin->vg->extent_size;
1143 : :
1144 [ # # ]: 0 : if (lv_is_merging_cow(lv)) {
1145 : : /* cow is to be merged so load the error target */
1146 [ # # ]: 0 : if (!dm_tree_node_add_error_target(dnode, size))
1147 : 0 : return_0;
1148 : : }
1149 [ # # ]: 0 : else if (!dm_tree_node_add_snapshot_target(dnode, size, origin_dlid,
1150 : : cow_dlid, 1, snap_seg->chunk_size))
1151 : 0 : return_0;
1152 : :
1153 : 0 : return 1;
1154 : : }
1155 : :
1156 : 0 : static int _add_target_to_dtree(struct dev_manager *dm,
1157 : : struct dm_tree_node *dnode,
1158 : : struct lv_segment *seg)
1159 : : {
1160 : 0 : uint64_t extent_size = seg->lv->vg->extent_size;
1161 : :
1162 [ # # ]: 0 : if (!seg->segtype->ops->add_target_line) {
1163 : 0 : log_error(INTERNAL_ERROR "_emit_target cannot handle "
1164 : : "segment type %s", seg->segtype->name);
1165 : 0 : return 0;
1166 : : }
1167 : :
1168 : 0 : return seg->segtype->ops->add_target_line(dm, dm->mem, dm->cmd,
1169 : : &dm->target_state, seg,
1170 : : dnode,
1171 : : extent_size * seg->len,
1172 : : &dm-> pvmove_mirror_count);
1173 : : }
1174 : :
1175 : : static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
1176 : : struct logical_volume *lv, const char *layer);
1177 : :
1178 : : /* Add all replicators' LVs from active segment */
1179 : 0 : static int _add_replicator_dev_target_to_dtree(struct dev_manager *dm,
1180 : : struct dm_tree *dtree,
1181 : : struct lv_segment *seg)
1182 : : {
1183 : : struct replicator_device *rdev;
1184 : : struct replicator_site *rsite;
1185 : :
1186 : : /* Only active replicator */
1187 [ # # ]: 0 : if (!lv_is_active_replicator_dev(seg->lv)) {
1188 [ # # ]: 0 : if (!_add_new_lv_to_dtree(dm, dtree, seg->lv->rdevice->lv, NULL))
1189 : 0 : return_0;
1190 : 0 : return 1;
1191 : : }
1192 : :
1193 : : /* Add rlog and replicator nodes */
1194 [ # # # # # : 0 : if (!seg->replicator ||
# # # ]
1195 : 0 : !first_seg(seg->replicator)->rlog_lv ||
1196 : 0 : !_add_new_lv_to_dtree(dm, dtree,
1197 : 0 : first_seg(seg->replicator)->rlog_lv, NULL) ||
1198 : 0 : !_add_new_lv_to_dtree(dm, dtree, seg->replicator, NULL))
1199 : 0 : return_0;
1200 : :
1201 : : /* Activation of one replicator_dev node activates all other nodes */
1202 [ # # ]: 0 : dm_list_iterate_items(rsite, &seg->replicator->rsites) {
1203 [ # # ]: 0 : dm_list_iterate_items(rdev, &rsite->rdevices) {
1204 : 0 : log_very_verbose("#####ADDD#### site:%s dev:%s sites:%d lv:%p sl:%p",
1205 : : rsite->name, rdev->name,
1206 : : rsite->state, rdev->lv,
1207 : : rdev->slog);
1208 [ # # # # ]: 0 : if (rdev->lv &&
1209 : 0 : !_add_new_lv_to_dtree(dm, dtree, rdev->lv, NULL))
1210 : 0 : return_0;
1211 : :
1212 [ # # # # ]: 0 : if (rdev->slog &&
1213 : 0 : !_add_new_lv_to_dtree(dm, dtree,
1214 : : rdev->slog, NULL))
1215 : 0 : return_0;
1216 : : }
1217 : : }
1218 : : /* Add remaining replicator-dev nodes in the second loop
1219 : : * to avoid multiple retries for inserting all elements */
1220 [ # # ]: 0 : dm_list_iterate_items(rsite, &seg->replicator->rsites) {
1221 [ # # ]: 0 : if (rsite->state != REPLICATOR_STATE_ACTIVE)
1222 : 0 : continue;
1223 [ # # ]: 0 : dm_list_iterate_items(rdev, &rsite->rdevices) {
1224 [ # # ]: 0 : if (rdev->replicator_dev->lv == seg->lv)
1225 : 0 : continue;
1226 [ # # # # ]: 0 : if (!rdev->replicator_dev->lv ||
1227 : 0 : !_add_new_lv_to_dtree(dm, dtree,
1228 : 0 : rdev->replicator_dev->lv,
1229 : : NULL))
1230 : 0 : return_0;
1231 : : }
1232 : : }
1233 : :
1234 : 0 : return 1;
1235 : : }
1236 : :
1237 : 0 : static int _add_segment_to_dtree(struct dev_manager *dm,
1238 : : struct dm_tree *dtree,
1239 : : struct dm_tree_node *dnode,
1240 : : struct lv_segment *seg,
1241 : : const char *layer)
1242 : : {
1243 : : uint32_t s;
1244 : : struct dm_list *snh;
1245 : : struct lv_segment *seg_present;
1246 : :
1247 : : /* Ensure required device-mapper targets are loaded */
1248 [ # # ]: 0 : seg_present = find_cow(seg->lv) ? : seg;
1249 : :
1250 [ # # ][ # # ]: 0 : log_debug("Checking kernel supports %s segment type for %s%s%s",
1251 : : seg_present->segtype->name, seg->lv->name,
1252 : : layer ? "-" : "", layer ? : "");
1253 : :
1254 [ # # # # ]: 0 : if (seg_present->segtype->ops->target_present &&
1255 : 0 : !seg_present->segtype->ops->target_present(seg_present->lv->vg->cmd,
1256 : : seg_present, NULL)) {
1257 : 0 : log_error("Can't expand LV %s: %s target support missing "
1258 : : "from kernel?", seg->lv->name, seg_present->segtype->name);
1259 : 0 : return 0;
1260 : : }
1261 : :
1262 : : /* Add mirror log */
1263 [ # # # # ]: 0 : if (seg->log_lv &&
1264 : 0 : !_add_new_lv_to_dtree(dm, dtree, seg->log_lv, NULL))
1265 : 0 : return_0;
1266 : :
1267 [ # # ]: 0 : if (seg_is_replicator_dev(seg)) {
1268 [ # # ]: 0 : if (!_add_replicator_dev_target_to_dtree(dm, dtree, seg))
1269 : 0 : return_0;
1270 : : /* If this is a snapshot origin, add real LV */
1271 : : /* If this is a snapshot origin + merging snapshot, add cow + real LV */
1272 [ # # ][ # # ]: 0 : } else if (lv_is_origin(seg->lv) && !layer) {
1273 [ # # ]: 0 : if (vg_is_clustered(seg->lv->vg)) {
1274 : 0 : log_error("Clustered snapshots are not yet supported");
1275 : 0 : return 0;
1276 : : }
1277 [ # # ]: 0 : if (lv_is_merging_origin(seg->lv)) {
1278 [ # # ]: 0 : if (!_add_new_lv_to_dtree(dm, dtree,
1279 : 0 : find_merging_cow(seg->lv)->cow, "cow"))
1280 : 0 : return_0;
1281 : : /*
1282 : : * Must also add "real" LV for use when
1283 : : * snapshot-merge target is added
1284 : : */
1285 : : }
1286 [ # # ]: 0 : if (!_add_new_lv_to_dtree(dm, dtree, seg->lv, "real"))
1287 : 0 : return_0;
1288 [ # # ][ # # ]: 0 : } else if (lv_is_cow(seg->lv) && !layer) {
1289 [ # # ]: 0 : if (!_add_new_lv_to_dtree(dm, dtree, seg->lv, "cow"))
1290 : 0 : return_0;
1291 : : } else {
1292 : : /* Add any LVs used by this segment */
1293 [ # # ]: 0 : for (s = 0; s < seg->area_count; s++)
1294 [ # # # # ]: 0 : if ((seg_type(seg, s) == AREA_LV) &&
1295 : 0 : (!_add_new_lv_to_dtree(dm, dtree, seg_lv(seg, s),
1296 : : NULL)))
1297 : 0 : return_0;
1298 : : }
1299 : :
1300 : : /* Now we've added its dependencies, we can add the target itself */
1301 [ # # ][ # # ]: 0 : if (lv_is_origin(seg->lv) && !layer) {
1302 [ # # ]: 0 : if (!lv_is_merging_origin(seg->lv)) {
1303 [ # # ]: 0 : if (!_add_origin_target_to_dtree(dm, dnode, seg->lv))
1304 : 0 : return_0;
1305 : : } else {
1306 [ # # ]: 0 : if (!_add_snapshot_merge_target_to_dtree(dm, dnode, seg->lv))
1307 : 0 : return_0;
1308 : : }
1309 [ # # ][ # # ]: 0 : } else if (lv_is_cow(seg->lv) && !layer) {
1310 [ # # ]: 0 : if (!_add_snapshot_target_to_dtree(dm, dnode, seg->lv))
1311 : 0 : return_0;
1312 [ # # ]: 0 : } else if (!_add_target_to_dtree(dm, dnode, seg))
1313 : 0 : return_0;
1314 : :
1315 [ # # ][ # # ]: 0 : if (lv_is_origin(seg->lv) && !layer)
1316 : : /* Add any snapshots of this LV */
1317 [ # # ]: 0 : dm_list_iterate(snh, &seg->lv->snapshot_segs)
1318 [ # # ]: 0 : if (!_add_new_lv_to_dtree(dm, dtree, dm_list_struct_base(snh, struct lv_segment, origin_list)->cow, NULL))
1319 : 0 : return_0;
1320 : :
1321 : 0 : return 1;
1322 : : }
1323 : :
1324 : 0 : static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
1325 : : struct logical_volume *lv, const char *layer)
1326 : : {
1327 : : struct lv_segment *seg;
1328 : : struct lv_layer *lvlayer;
1329 : : struct dm_tree_node *dnode;
1330 : : const struct dm_info *dinfo;
1331 : : char *name, *dlid;
1332 : 0 : uint32_t max_stripe_size = UINT32_C(0);
1333 : 0 : uint32_t read_ahead = lv->read_ahead;
1334 : 0 : uint32_t read_ahead_flags = UINT32_C(0);
1335 : 0 : uint16_t udev_flags = 0;
1336 : :
1337 : 0 : log_verbose("_add_new_lv_to_dtree: lv:%s l:%s vg:%s.", lv->name, layer, lv->vg->name);
1338 : : /* FIXME Seek a simpler way to lay out the snapshot-merge tree. */
1339 : :
1340 [ # # # # ]: 0 : if (lv_is_origin(lv) && lv_is_merging_origin(lv) && !layer) {
[ # # ]
1341 : : /*
1342 : : * Clear merge attributes if merge isn't currently possible:
1343 : : * either origin or merging snapshot are open
1344 : : * - but use "snapshot-merge" if it is already in use
1345 : : * - open_count is always retrieved (as of dm-ioctl 4.7.0)
1346 : : * so just use the tree's existing nodes' info
1347 : : */
1348 [ # # ]: 0 : if (((dinfo = _cached_info(dm->mem, lv,
[ # # # # ]
[ # # ]
1349 : 0 : dtree)) && dinfo->open_count) ||
1350 : 0 : ((dinfo = _cached_info(dm->mem, find_merging_cow(lv)->cow,
1351 : 0 : dtree)) && dinfo->open_count)) {
1352 : : /* FIXME Is there anything simpler to check for instead? */
1353 [ # # ]: 0 : if (!_lv_has_target_type(dm, lv, NULL, "snapshot-merge"))
1354 : 0 : clear_snapshot_merge(lv);
1355 : : }
1356 : : }
1357 : :
1358 [ # # ]: 0 : if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
1359 : 0 : return_0;
1360 : :
1361 [ # # ]: 0 : if (!(dlid = build_dlid(dm, lv->lvid.s, layer)))
1362 : 0 : return_0;
1363 : :
1364 : : /* We've already processed this node if it already has a context ptr */
1365 [ # # # # ]: 0 : if ((dnode = dm_tree_find_node_by_uuid(dtree, dlid)) &&
1366 : 0 : dm_tree_node_get_context(dnode))
1367 : 0 : return 1;
1368 : :
1369 [ # # ]: 0 : if (!(lvlayer = dm_pool_alloc(dm->mem, sizeof(*lvlayer)))) {
1370 : 0 : log_error("_add_new_lv_to_dtree: pool alloc failed for %s %s.",
1371 : : lv->name, layer);
1372 : 0 : return 0;
1373 : : }
1374 : :
1375 : 0 : lvlayer->lv = lv;
1376 : :
1377 [ # # ][ # # ]: 0 : if (layer || !lv_is_visible(lv))
1378 : 0 : udev_flags |= DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG |
1379 : : DM_UDEV_DISABLE_DISK_RULES_FLAG |
1380 : : DM_UDEV_DISABLE_OTHER_RULES_FLAG;
1381 : :
1382 [ # # ]: 0 : if (lv_is_cow(lv))
1383 : 0 : udev_flags |= DM_UDEV_LOW_PRIORITY_FLAG;
1384 : :
1385 [ # # ]: 0 : if (!dm->cmd->current_settings.udev_rules)
1386 : 0 : udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG |
1387 : : DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG;
1388 : :
1389 : : /*
1390 : : * Add LV to dtree.
1391 : : * If we're working with precommitted metadata, clear any
1392 : : * existing inactive table left behind.
1393 : : * Major/minor settings only apply to the visible layer.
1394 : : */
1395 [ # # ][ # # ]: 0 : if (!(dnode = dm_tree_add_new_dev_with_udev_flags(dtree, name, dlid,
[ # # ]
1396 : 0 : layer ? UINT32_C(0) : (uint32_t) lv->major,
1397 : 0 : layer ? UINT32_C(0) : (uint32_t) lv->minor,
1398 : : _read_only_lv(lv),
1399 : 0 : (lv->vg->status & PRECOMMITTED) ? 1 : 0,
1400 : : lvlayer,
1401 : : udev_flags)))
1402 : 0 : return_0;
1403 : :
1404 : : /* Store existing name so we can do rename later */
1405 : 0 : lvlayer->old_name = dm_tree_node_get_name(dnode);
1406 : :
1407 : : /* Create table */
1408 : 0 : dm->pvmove_mirror_count = 0u;
1409 [ # # ]: 0 : dm_list_iterate_items(seg, &lv->segments) {
1410 [ # # ]: 0 : if (!_add_segment_to_dtree(dm, dtree, dnode, seg, layer))
1411 : 0 : return_0;
1412 : : /* These aren't real segments in the LVM2 metadata */
1413 [ # # ][ # # ]: 0 : if (lv_is_origin(lv) && !layer)
1414 : 0 : break;
1415 [ # # ][ # # ]: 0 : if (lv_is_cow(lv) && !layer)
1416 : 0 : break;
1417 [ # # ]: 0 : if (max_stripe_size < seg->stripe_size * seg->area_count)
1418 : 0 : max_stripe_size = seg->stripe_size * seg->area_count;
1419 : : }
1420 : :
1421 [ # # ]: 0 : if (read_ahead == DM_READ_AHEAD_AUTO) {
1422 : : /* we need RA at least twice a whole stripe - see the comment in md/raid0.c */
1423 : 0 : read_ahead = max_stripe_size * 2;
1424 [ # # ]: 0 : if (!read_ahead)
1425 : 0 : lv_calculate_readahead(lv, &read_ahead);
1426 : 0 : read_ahead_flags = DM_READ_AHEAD_MINIMUM_FLAG;
1427 : : }
1428 : :
1429 : 0 : dm_tree_node_set_read_ahead(dnode, read_ahead, read_ahead_flags);
1430 : :
1431 : 0 : return 1;
1432 : : }
1433 : :
1434 : : /* FIXME: symlinks should be created/destroyed at the same time
1435 : : * as the kernel devices but we can't do that from within libdevmapper
1436 : : * at present so we must walk the tree twice instead. */
1437 : :
1438 : : /*
1439 : : * Create LV symlinks for children of supplied root node.
1440 : : */
1441 : 0 : static int _create_lv_symlinks(struct dev_manager *dm, struct dm_tree_node *root)
1442 : : {
1443 : 0 : void *handle = NULL;
1444 : : struct dm_tree_node *child;
1445 : : struct lv_layer *lvlayer;
1446 : : char *old_vgname, *old_lvname, *old_layer;
1447 : : char *new_vgname, *new_lvname, *new_layer;
1448 : : const char *name;
1449 : 0 : int r = 1;
1450 : :
1451 [ # # ]: 0 : while ((child = dm_tree_next_child(&handle, root, 0))) {
1452 [ # # ]: 0 : if (!(lvlayer = dm_tree_node_get_context(child)))
1453 : 0 : continue;
1454 : :
1455 : : /* Detect rename */
1456 : 0 : name = dm_tree_node_get_name(child);
1457 : :
1458 [ # # # # ]: 0 : if (name && lvlayer->old_name && *lvlayer->old_name && strcmp(name, lvlayer->old_name)) {
[ # # ][ # # ]
1459 [ # # ]: 0 : if (!dm_split_lvm_name(dm->mem, lvlayer->old_name, &old_vgname, &old_lvname, &old_layer)) {
1460 : 0 : log_error("_create_lv_symlinks: Couldn't split up old device name %s", lvlayer->old_name);
1461 : 0 : return 0;
1462 : : }
1463 [ # # ]: 0 : if (!dm_split_lvm_name(dm->mem, name, &new_vgname, &new_lvname, &new_layer)) {
1464 : 0 : log_error("_create_lv_symlinks: Couldn't split up new device name %s", name);
1465 : 0 : return 0;
1466 : : }
1467 [ # # ]: 0 : if (!fs_rename_lv(lvlayer->lv, name, old_vgname, old_lvname))
1468 : 0 : r = 0;
1469 : 0 : continue;
1470 : : }
1471 [ # # ]: 0 : if (lv_is_visible(lvlayer->lv)) {
1472 [ # # ]: 0 : if (!_dev_manager_lv_mknodes(lvlayer->lv))
1473 : 0 : r = 0;
1474 : 0 : continue;
1475 : : }
1476 [ # # ]: 0 : if (!_dev_manager_lv_rmnodes(lvlayer->lv))
1477 : 0 : r = 0;
1478 : : }
1479 : :
1480 : 0 : return r;
1481 : : }
1482 : :
1483 : : /*
1484 : : * Remove LV symlinks for children of supplied root node.
1485 : : */
1486 : 0 : static int _remove_lv_symlinks(struct dev_manager *dm, struct dm_tree_node *root)
1487 : : {
1488 : 0 : void *handle = NULL;
1489 : : struct dm_tree_node *child;
1490 : : char *vgname, *lvname, *layer;
1491 : 0 : int r = 1;
1492 : :
1493 [ # # ]: 0 : while ((child = dm_tree_next_child(&handle, root, 0))) {
1494 [ # # ]: 0 : if (!dm_split_lvm_name(dm->mem, dm_tree_node_get_name(child), &vgname, &lvname, &layer)) {
1495 : 0 : r = 0;
1496 : 0 : continue;
1497 : : }
1498 : :
1499 [ # # ]: 0 : if (!*vgname)
1500 : 0 : continue;
1501 : :
1502 : : /* only top level layer has symlinks */
1503 [ # # ]: 0 : if (*layer)
1504 : 0 : continue;
1505 : :
1506 : 0 : fs_del_lv_byname(dm->cmd->dev_dir, vgname, lvname,
1507 : 0 : dm->cmd->current_settings.udev_rules);
1508 : : }
1509 : :
1510 : 0 : return r;
1511 : : }
1512 : :
1513 : 0 : static int _clean_tree(struct dev_manager *dm, struct dm_tree_node *root)
1514 : : {
1515 : 0 : void *handle = NULL;
1516 : : struct dm_tree_node *child;
1517 : : char *vgname, *lvname, *layer;
1518 : : const char *name, *uuid;
1519 : : int r;
1520 : :
1521 [ # # ]: 0 : while ((child = dm_tree_next_child(&handle, root, 0))) {
1522 [ # # ]: 0 : if (!(name = dm_tree_node_get_name(child)))
1523 : 0 : continue;
1524 : :
1525 [ # # ]: 0 : if (!(uuid = dm_tree_node_get_uuid(child)))
1526 : 0 : continue;
1527 : :
1528 [ # # ]: 0 : if (!dm_split_lvm_name(dm->mem, name, &vgname, &lvname, &layer)) {
1529 : 0 : log_error("_clean_tree: Couldn't split up device name %s.", name);
1530 : 0 : return 0;
1531 : : }
1532 : :
1533 : : /* Not meant to be top level? */
1534 [ # # ]: 0 : if (!*layer)
1535 : 0 : continue;
1536 : :
1537 : 0 : dm_tree_set_cookie(root, 0);
1538 : 0 : r = dm_tree_deactivate_children(root, uuid, strlen(uuid));
1539 [ # # ]: 0 : if (!dm_udev_wait(dm_tree_get_cookie(root)))
1540 : 0 : stack;
1541 : :
1542 [ # # ]: 0 : if (!r)
1543 : 0 : return_0;
1544 : : }
1545 : :
1546 : 0 : return 1;
1547 : : }
1548 : :
1549 : 0 : static int _tree_action(struct dev_manager *dm, struct logical_volume *lv, action_t action)
1550 : : {
1551 : : struct dm_tree *dtree;
1552 : : struct dm_tree_node *root;
1553 : : char *dlid;
1554 : 0 : int r = 0;
1555 : :
1556 [ # # ]: 0 : if (!(dtree = _create_partial_dtree(dm, lv)))
1557 : 0 : return_0;
1558 : :
1559 [ # # ]: 0 : if (!(root = dm_tree_find_node(dtree, 0, 0))) {
1560 : 0 : log_error("Lost dependency tree root node");
1561 : 0 : goto out;
1562 : : }
1563 : :
1564 [ # # ]: 0 : if (!(dlid = build_dlid(dm, lv->lvid.s, NULL)))
1565 : 0 : goto_out;
1566 : :
1567 : : /* Only process nodes with uuid of "LVM-" plus VG id. */
1568 [ # # # # # : 0 : switch(action) {
# ]
1569 : : case CLEAN:
1570 : : /* Deactivate any unused non-toplevel nodes */
1571 [ # # ]: 0 : if (!_clean_tree(dm, root))
1572 : 0 : goto_out;
1573 : 0 : break;
1574 : : case DEACTIVATE:
1575 : : /* Deactivate LV and all devices it references that nothing else has open. */
1576 : 0 : dm_tree_set_cookie(root, 0);
1577 : 0 : r = dm_tree_deactivate_children(root, dlid, ID_LEN + sizeof(UUID_PREFIX) - 1);
1578 [ # # ]: 0 : if (!dm_udev_wait(dm_tree_get_cookie(root)))
1579 : 0 : stack;
1580 [ # # ]: 0 : if (!r)
1581 : 0 : goto_out;
1582 [ # # ]: 0 : if (!_remove_lv_symlinks(dm, root))
1583 : 0 : log_error("Failed to remove all device symlinks associated with %s.", lv->name);
1584 : 0 : break;
1585 : : case SUSPEND:
1586 : 0 : dm_tree_skip_lockfs(root);
1587 [ # # # # ]: 0 : if (!dm->flush_required && (lv->status & MIRRORED) && !(lv->status & PVMOVE))
[ # # ]
1588 : 0 : dm_tree_use_no_flush_suspend(root);
1589 : : case SUSPEND_WITH_LOCKFS:
1590 [ # # ]: 0 : if (!dm_tree_suspend_children(root, dlid, ID_LEN + sizeof(UUID_PREFIX) - 1))
1591 : 0 : goto_out;
1592 : 0 : break;
1593 : : case PRELOAD:
1594 : : case ACTIVATE:
1595 : : /* Add all required new devices to tree */
1596 [ # # ]: 0 : if (!_add_new_lv_to_dtree(dm, dtree, lv, NULL))
1597 : 0 : goto_out;
1598 : :
1599 : : /* Preload any devices required before any suspensions */
1600 : 0 : dm_tree_set_cookie(root, 0);
1601 : 0 : r = dm_tree_preload_children(root, dlid, ID_LEN + sizeof(UUID_PREFIX) - 1);
1602 [ # # ]: 0 : if (!dm_udev_wait(dm_tree_get_cookie(root)))
1603 : 0 : stack;
1604 [ # # ]: 0 : if (!r)
1605 : 0 : goto_out;
1606 : :
1607 [ # # ]: 0 : if (dm_tree_node_size_changed(root))
1608 : 0 : dm->flush_required = 1;
1609 : :
1610 [ # # ]: 0 : if (action == ACTIVATE) {
1611 : 0 : dm_tree_set_cookie(root, 0);
1612 : 0 : r = dm_tree_activate_children(root, dlid, ID_LEN + sizeof(UUID_PREFIX) - 1);
1613 [ # # ]: 0 : if (!dm_udev_wait(dm_tree_get_cookie(root)))
1614 : 0 : stack;
1615 [ # # ]: 0 : if (!r)
1616 : 0 : goto_out;
1617 [ # # ]: 0 : if (!_create_lv_symlinks(dm, root)) {
1618 : 0 : log_error("Failed to create symlinks for %s.", lv->name);
1619 : 0 : goto out;
1620 : : }
1621 : : }
1622 : :
1623 : 0 : break;
1624 : : default:
1625 : 0 : log_error("_tree_action: Action %u not supported.", action);
1626 : 0 : goto out;
1627 : : }
1628 : :
1629 : 0 : r = 1;
1630 : :
1631 : : out:
1632 : 0 : dm_tree_free(dtree);
1633 : :
1634 : 0 : return r;
1635 : : }
1636 : :
1637 : 0 : int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv)
1638 : : {
1639 [ # # ]: 0 : if (!_tree_action(dm, lv, ACTIVATE))
1640 : 0 : return_0;
1641 : :
1642 : 0 : return _tree_action(dm, lv, CLEAN);
1643 : : }
1644 : :
1645 : 0 : int dev_manager_preload(struct dev_manager *dm, struct logical_volume *lv,
1646 : : int *flush_required)
1647 : : {
1648 : : /* FIXME Update the pvmove implementation! */
1649 [ # # ][ # # ]: 0 : if ((lv->status & PVMOVE) || (lv->status & LOCKED))
1650 : 0 : return 1;
1651 : :
1652 [ # # ]: 0 : if (!_tree_action(dm, lv, PRELOAD))
1653 : 0 : return 0;
1654 : :
1655 : 0 : *flush_required = dm->flush_required;
1656 : :
1657 : 0 : return 1;
1658 : : }
1659 : :
1660 : 0 : int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv)
1661 : : {
1662 : : int r;
1663 : :
1664 : 0 : r = _tree_action(dm, lv, DEACTIVATE);
1665 : :
1666 : 0 : return r;
1667 : : }
1668 : :
1669 : 0 : int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv,
1670 : : int lockfs, int flush_required)
1671 : : {
1672 : 0 : dm->flush_required = flush_required;
1673 : :
1674 [ # # ]: 0 : return _tree_action(dm, lv, lockfs ? SUSPEND_WITH_LOCKFS : SUSPEND);
1675 : : }
1676 : :
1677 : : /*
1678 : : * Does device use VG somewhere in its construction?
1679 : : * Returns 1 if uncertain.
1680 : : */
1681 : 0 : int dev_manager_device_uses_vg(struct device *dev,
1682 : : struct volume_group *vg)
1683 : : {
1684 : : struct dm_tree *dtree;
1685 : : struct dm_tree_node *root;
1686 : : char dlid[sizeof(UUID_PREFIX) + sizeof(struct id) - 1] __attribute((aligned(8)));
1687 : 0 : int r = 1;
1688 : :
1689 [ # # ]: 0 : if (!(dtree = dm_tree_create())) {
1690 : 0 : log_error("partial dtree creation failed");
1691 : 0 : return r;
1692 : : }
1693 : :
1694 [ # # ]: 0 : if (!dm_tree_add_dev(dtree, (uint32_t) MAJOR(dev->dev), (uint32_t) MINOR(dev->dev))) {
1695 : 0 : log_error("Failed to add device %s (%" PRIu32 ":%" PRIu32") to dtree",
1696 : : dev_name(dev), (uint32_t) MAJOR(dev->dev), (uint32_t) MINOR(dev->dev));
1697 : 0 : goto out;
1698 : : }
1699 : :
1700 : 0 : memcpy(dlid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1);
1701 : 0 : memcpy(dlid + sizeof(UUID_PREFIX) - 1, &vg->id.uuid[0], sizeof(vg->id));
1702 : :
1703 [ # # ]: 0 : if (!(root = dm_tree_find_node(dtree, 0, 0))) {
1704 : 0 : log_error("Lost dependency tree root node");
1705 : 0 : goto out;
1706 : : }
1707 : :
1708 [ # # ]: 0 : if (dm_tree_children_use_uuid(root, dlid, sizeof(UUID_PREFIX) + sizeof(vg->id) - 1))
1709 : 0 : goto_out;
1710 : :
1711 : 0 : r = 0;
1712 : :
1713 : : out:
1714 : 0 : dm_tree_free(dtree);
1715 : 0 : return r;
1716 : : }
|