Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2003-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 "tools.h"
17 : : #include "polldaemon.h"
18 : : #include "display.h"
19 : :
20 : : #define PVMOVE_FIRST_TIME 0x00000001 /* Called for first time */
21 : :
22 : 0 : static int _pvmove_target_present(struct cmd_context *cmd, int clustered)
23 : : {
24 : : const struct segment_type *segtype;
25 : 0 : unsigned attr = 0;
26 : 0 : int found = 1;
27 : : static int _clustered_found = -1;
28 : :
29 [ # # ][ # # ]: 0 : if (clustered && _clustered_found >= 0)
30 : 0 : return _clustered_found;
31 : :
32 [ # # ]: 0 : if (!(segtype = get_segtype_from_string(cmd, "mirror")))
33 : 0 : return_0;
34 : :
35 [ # # ]: 0 : if (activation() && segtype->ops->target_present &&
[ # # # # ]
36 [ # # ]: 0 : !segtype->ops->target_present(cmd, NULL, clustered ? &attr : NULL))
37 : 0 : found = 0;
38 : :
39 [ # # ][ # # ]: 0 : if (activation() && clustered) {
40 [ # # ][ # # ]: 0 : if (found && (attr & MIRROR_LOG_CLUSTERED))
41 : 0 : _clustered_found = found = 1;
42 : : else
43 : 0 : _clustered_found = found = 0;
44 : : }
45 : :
46 : 0 : return found;
47 : : }
48 : :
49 : 0 : static unsigned _pvmove_is_exclusive(struct cmd_context *cmd,
50 : : struct volume_group *vg)
51 : : {
52 [ # # ]: 0 : if (vg_is_clustered(vg))
53 [ # # ]: 0 : if (!_pvmove_target_present(cmd, 1))
54 : 0 : return 1;
55 : :
56 : 0 : return 0;
57 : : }
58 : :
59 : : /* Allow /dev/vgname/lvname, vgname/lvname or lvname */
60 : 0 : static const char *_extract_lvname(struct cmd_context *cmd, const char *vgname,
61 : : const char *arg)
62 : : {
63 : : const char *lvname;
64 : :
65 : : /* Is an lvname supplied directly? */
66 [ # # ]: 0 : if (!strchr(arg, '/'))
67 : 0 : return arg;
68 : :
69 : 0 : lvname = skip_dev_dir(cmd, arg, NULL);
70 [ # # ]: 0 : while (*lvname == '/')
71 : 0 : lvname++;
72 [ # # ]: 0 : if (!strchr(lvname, '/')) {
73 : 0 : log_error("--name takes a logical volume name");
74 : 0 : return NULL;
75 : : }
76 [ # # ][ # # ]: 0 : if (strncmp(vgname, lvname, strlen(vgname)) ||
77 : 0 : (lvname += strlen(vgname), *lvname != '/')) {
78 : 0 : log_error("Named LV and old PV must be in the same VG");
79 : 0 : return NULL;
80 : : }
81 [ # # ]: 0 : while (*lvname == '/')
82 : 0 : lvname++;
83 [ # # ]: 0 : if (!*lvname) {
84 : 0 : log_error("Incomplete LV name supplied with --name");
85 : 0 : return NULL;
86 : : }
87 : 0 : return lvname;
88 : : }
89 : :
90 : 0 : static struct volume_group *_get_vg(struct cmd_context *cmd, const char *vgname)
91 : : {
92 : 0 : dev_close_all();
93 : :
94 : 0 : return vg_read_for_update(cmd, vgname, NULL, 0);
95 : : }
96 : :
97 : : /* Create list of PVs for allocation of replacement extents */
98 : 0 : static struct dm_list *_get_allocatable_pvs(struct cmd_context *cmd, int argc,
99 : : char **argv, struct volume_group *vg,
100 : : struct physical_volume *pv,
101 : : alloc_policy_t alloc)
102 : : {
103 : : struct dm_list *allocatable_pvs, *pvht, *pvh;
104 : : struct pv_list *pvl;
105 : :
106 [ # # ]: 0 : if (argc)
107 : 0 : allocatable_pvs = create_pv_list(cmd->mem, vg, argc, argv, 1);
108 : : else
109 : 0 : allocatable_pvs = clone_pv_list(cmd->mem, &vg->pvs);
110 : :
111 [ # # ]: 0 : if (!allocatable_pvs)
112 : 0 : return_NULL;
113 : :
114 [ # # ]: 0 : dm_list_iterate_safe(pvh, pvht, allocatable_pvs) {
115 : 0 : pvl = dm_list_item(pvh, struct pv_list);
116 : :
117 : : /* Don't allocate onto the PV we're clearing! */
118 [ # # ][ # # ]: 0 : if ((alloc != ALLOC_ANYWHERE) && (pvl->pv->dev == pv_dev(pv))) {
119 : 0 : dm_list_del(&pvl->list);
120 : 0 : continue;
121 : : }
122 : :
123 : : /* Remove PV if full */
124 [ # # ]: 0 : if ((pvl->pv->pe_count == pvl->pv->pe_alloc_count))
125 : 0 : dm_list_del(&pvl->list);
126 : : }
127 : :
128 [ # # ]: 0 : if (dm_list_empty(allocatable_pvs)) {
129 : 0 : log_error("No extents available for allocation");
130 : 0 : return NULL;
131 : : }
132 : :
133 : 0 : return allocatable_pvs;
134 : : }
135 : :
136 : : /*
137 : : * Replace any LV segments on given PV with temporary mirror.
138 : : * Returns list of LVs changed.
139 : : */
140 : 0 : static int _insert_pvmove_mirrors(struct cmd_context *cmd,
141 : : struct logical_volume *lv_mirr,
142 : : struct dm_list *source_pvl,
143 : : struct logical_volume *lv,
144 : : struct dm_list *lvs_changed)
145 : :
146 : : {
147 : : struct pv_list *pvl;
148 : : uint32_t prev_le_count;
149 : :
150 : : /* Only 1 PV may feature in source_pvl */
151 : 0 : pvl = dm_list_item(source_pvl->n, struct pv_list);
152 : :
153 : 0 : prev_le_count = lv_mirr->le_count;
154 [ # # ]: 0 : if (!insert_layer_for_segments_on_pv(cmd, lv, lv_mirr, PVMOVE,
155 : : pvl, lvs_changed))
156 : 0 : return_0;
157 : :
158 : : /* check if layer was inserted */
159 [ # # ]: 0 : if (lv_mirr->le_count - prev_le_count) {
160 : 0 : lv->status |= LOCKED;
161 : :
162 : 0 : log_verbose("Moving %u extents of logical volume %s/%s",
163 : : lv_mirr->le_count - prev_le_count,
164 : : lv->vg->name, lv->name);
165 : : }
166 : :
167 : 0 : return 1;
168 : : }
169 : :
170 : : /* Create new LV with mirror segments for the required copies */
171 : 0 : static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
172 : : struct volume_group *vg,
173 : : struct dm_list *source_pvl,
174 : : const char *lv_name,
175 : : struct dm_list *allocatable_pvs,
176 : : alloc_policy_t alloc,
177 : : struct dm_list **lvs_changed)
178 : : {
179 : : struct logical_volume *lv_mirr, *lv;
180 : : struct lv_list *lvl;
181 : 0 : uint32_t log_count = 0;
182 : 0 : int lv_found = 0;
183 : 0 : int lv_skipped = 0;
184 : :
185 : : /* FIXME Cope with non-contiguous => splitting existing segments */
186 [ # # ]: 0 : if (!(lv_mirr = lv_create_empty("pvmove%d", NULL,
187 : : LVM_READ | LVM_WRITE,
188 : : ALLOC_CONTIGUOUS, vg))) {
189 : 0 : log_error("Creation of temporary pvmove LV failed");
190 : 0 : return NULL;
191 : : }
192 : :
193 : 0 : lv_mirr->status |= (PVMOVE | LOCKED);
194 : :
195 [ # # ]: 0 : if (!(*lvs_changed = dm_pool_alloc(cmd->mem, sizeof(**lvs_changed)))) {
196 : 0 : log_error("lvs_changed list struct allocation failed");
197 : 0 : return NULL;
198 : : }
199 : :
200 : 0 : dm_list_init(*lvs_changed);
201 : :
202 : : /* Find segments to be moved and set up mirrors */
203 [ # # ]: 0 : dm_list_iterate_items(lvl, &vg->lvs) {
204 : 0 : lv = lvl->lv;
205 [ # # ]: 0 : if ((lv == lv_mirr))
206 : 0 : continue;
207 [ # # ]: 0 : if (lv_name) {
208 [ # # ]: 0 : if (strcmp(lv->name, lv_name))
209 : 0 : continue;
210 : 0 : lv_found = 1;
211 : : }
212 [ # # ][ # # ]: 0 : if (lv_is_origin(lv) || lv_is_cow(lv)) {
213 : 0 : lv_skipped = 1;
214 : 0 : log_print("Skipping snapshot-related LV %s", lv->name);
215 : 0 : continue;
216 : : }
217 [ # # ]: 0 : if (lv->status & MIRRORED) {
218 : 0 : lv_skipped = 1;
219 : 0 : log_print("Skipping mirror LV %s", lv->name);
220 : 0 : continue;
221 : : }
222 [ # # ]: 0 : if (lv->status & MIRROR_LOG) {
223 : 0 : lv_skipped = 1;
224 : 0 : log_print("Skipping mirror log LV %s", lv->name);
225 : 0 : continue;
226 : : }
227 [ # # ]: 0 : if (lv->status & MIRROR_IMAGE) {
228 : 0 : lv_skipped = 1;
229 : 0 : log_print("Skipping mirror image LV %s", lv->name);
230 : 0 : continue;
231 : : }
232 [ # # ]: 0 : if (lv->status & LOCKED) {
233 : 0 : lv_skipped = 1;
234 : 0 : log_print("Skipping locked LV %s", lv->name);
235 : 0 : continue;
236 : : }
237 [ # # ]: 0 : if (!_insert_pvmove_mirrors(cmd, lv_mirr, source_pvl, lv,
238 : : *lvs_changed))
239 : 0 : return_NULL;
240 : : }
241 : :
242 [ # # ][ # # ]: 0 : if (lv_name && !lv_found) {
243 : 0 : log_error("Logical volume %s not found.", lv_name);
244 : 0 : return NULL;
245 : : }
246 : :
247 : : /* Is temporary mirror empty? */
248 [ # # ]: 0 : if (!lv_mirr->le_count) {
249 [ # # ]: 0 : if (lv_skipped)
250 : 0 : log_error("All data on source PV skipped. "
251 : : "It contains locked, hidden or "
252 : : "non-top level LVs only.");
253 : 0 : log_error("No data to move for %s", vg->name);
254 : 0 : return NULL;
255 : : }
256 : :
257 [ # # ]: 0 : if (!lv_add_mirrors(cmd, lv_mirr, 1, 1, 0, 0, log_count,
258 : : allocatable_pvs, alloc, MIRROR_BY_SEG)) {
259 : 0 : log_error("Failed to convert pvmove LV to mirrored");
260 : 0 : return_NULL;
261 : : }
262 : :
263 [ # # ]: 0 : if (!split_parent_segments_for_layer(cmd, lv_mirr)) {
264 : 0 : log_error("Failed to split segments being moved");
265 : 0 : return_NULL;
266 : : }
267 : :
268 : 0 : return lv_mirr;
269 : : }
270 : :
271 : 0 : static int _activate_lv(struct cmd_context *cmd, struct logical_volume *lv_mirr,
272 : : unsigned exclusive)
273 : : {
274 : 0 : int r = 0;
275 : :
276 [ # # ]: 0 : if (exclusive)
277 [ # # ][ # # ]: 0 : r = activate_lv_excl(cmd, lv_mirr);
278 : : else
279 [ # # ][ # # ]: 0 : r = activate_lv(cmd, lv_mirr);
280 : :
281 [ # # ]: 0 : if (!r)
282 : 0 : stack;
283 : :
284 : 0 : return r;
285 : : }
286 : :
287 : 0 : static int _detach_pvmove_mirror(struct cmd_context *cmd,
288 : : struct logical_volume *lv_mirr)
289 : : {
290 : : struct dm_list lvs_completed;
291 : : struct lv_list *lvl;
292 : :
293 : : /* Update metadata to remove mirror segments and break dependencies */
294 : 0 : dm_list_init(&lvs_completed);
295 [ # # # # ]: 0 : if (!lv_remove_mirrors(cmd, lv_mirr, 1, 0, NULL, PVMOVE) ||
296 : 0 : !remove_layers_for_segments_all(cmd, lv_mirr, PVMOVE,
297 : : &lvs_completed)) {
298 : 0 : return 0;
299 : : }
300 : :
301 [ # # ]: 0 : dm_list_iterate_items(lvl, &lvs_completed)
302 : : /* FIXME Assumes only one pvmove at a time! */
303 : 0 : lvl->lv->status &= ~LOCKED;
304 : :
305 : 0 : return 1;
306 : : }
307 : :
308 : 0 : static int _update_metadata(struct cmd_context *cmd, struct volume_group *vg,
309 : : struct logical_volume *lv_mirr,
310 : : struct dm_list *lvs_changed, unsigned flags)
311 : : {
312 : 0 : unsigned exclusive = _pvmove_is_exclusive(cmd, vg);
313 : 0 : unsigned first_time = (flags & PVMOVE_FIRST_TIME) ? 1 : 0;
314 : 0 : int r = 0;
315 : :
316 : 0 : log_verbose("Updating volume group metadata");
317 [ # # ]: 0 : if (!vg_write(vg)) {
318 : 0 : log_error("ABORTING: Volume group metadata update failed.");
319 : 0 : return 0;
320 : : }
321 : :
322 : : /* Suspend lvs_changed */
323 [ # # ]: 0 : if (!suspend_lvs(cmd, lvs_changed)) {
324 : 0 : vg_revert(vg);
325 : 0 : goto_out;
326 : : }
327 : :
328 : : /* Suspend mirrors on subsequent calls */
329 [ # # ]: 0 : if (!first_time) {
330 [ # # ][ # # ]: 0 : if (!suspend_lv(cmd, lv_mirr)) {
[ # # ]
331 [ # # ]: 0 : if (!resume_lvs(cmd, lvs_changed))
332 : 0 : stack;
333 : 0 : vg_revert(vg);
334 : 0 : goto_out;
335 : : }
336 : : }
337 : :
338 : : /* Commit on-disk metadata */
339 [ # # ]: 0 : if (!vg_commit(vg)) {
340 : 0 : log_error("ABORTING: Volume group metadata update failed.");
341 [ # # ]: 0 : if (!first_time)
342 [ # # ][ # # ]: 0 : if (!resume_lv(cmd, lv_mirr))
[ # # ]
343 : 0 : stack;
344 [ # # ]: 0 : if (!resume_lvs(cmd, lvs_changed))
345 : 0 : stack;
346 : 0 : vg_revert(vg);
347 : 0 : goto out;
348 : : }
349 : :
350 : : /* Activate the temporary mirror LV */
351 : : /* Only the first mirror segment gets activated as a mirror */
352 : : /* FIXME: Add option to use a log */
353 [ # # ]: 0 : if (first_time) {
354 [ # # ]: 0 : if (!_activate_lv(cmd, lv_mirr, exclusive)) {
355 [ # # ]: 0 : if (test_mode()) {
356 : 0 : r = 1;
357 : 0 : goto out;
358 : : }
359 : :
360 : : /*
361 : : * FIXME: review ordering of operations above,
362 : : * temporary mirror should be preloaded in suspend.
363 : : * Also banned operation here when suspended.
364 : : * Nothing changed yet, try to revert pvmove.
365 : : */
366 : 0 : log_error("Temporary pvmove mirror activation failed.");
367 : :
368 : : /* Ensure that temporary mrror is deactivate even on other nodes. */
369 [ # # # # ]: 0 : (void)deactivate_lv(cmd, lv_mirr);
370 : :
371 : : /* Revert metadata */
372 [ # # # # # : 0 : if (!_detach_pvmove_mirror(cmd, lv_mirr) ||
# # # ]
373 : 0 : !lv_remove(lv_mirr) ||
374 : 0 : !vg_write(vg) || !vg_commit(vg))
375 : 0 : log_error("ABORTING: Restoring original configuration "
376 : : "before pvmove failed. Run pvmove --abort.");
377 : :
378 : : /* Unsuspend LVs */
379 [ # # ]: 0 : if(!resume_lvs(cmd, lvs_changed))
380 : 0 : stack;
381 : :
382 : 0 : goto out;
383 : : }
384 [ # # ][ # # ]: 0 : } else if (!resume_lv(cmd, lv_mirr)) {
[ # # ]
385 : 0 : log_error("Unable to reactivate logical volume \"%s\"",
386 : : lv_mirr->name);
387 [ # # ]: 0 : if (!resume_lvs(cmd, lvs_changed))
388 : 0 : stack;
389 : 0 : goto out;
390 : : }
391 : :
392 : : /* Unsuspend LVs */
393 [ # # ]: 0 : if (!resume_lvs(cmd, lvs_changed)) {
394 : 0 : log_error("Unable to resume logical volumes");
395 : 0 : goto out;
396 : : }
397 : :
398 : 0 : r = 1;
399 : : out:
400 : 0 : backup(vg);
401 : 0 : return r;
402 : : }
403 : :
404 : 0 : static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
405 : : int argc, char **argv)
406 : : {
407 : 0 : const char *lv_name = NULL;
408 : : char *pv_name_arg;
409 : : struct volume_group *vg;
410 : : struct dm_list *source_pvl;
411 : : struct dm_list *allocatable_pvs;
412 : : alloc_policy_t alloc;
413 : : struct dm_list *lvs_changed;
414 : : struct physical_volume *pv;
415 : : struct logical_volume *lv_mirr;
416 : 0 : unsigned first_time = 1;
417 : : unsigned exclusive;
418 : 0 : int r = ECMD_FAILED;
419 : :
420 : 0 : pv_name_arg = argv[0];
421 : 0 : argc--;
422 : 0 : argv++;
423 : :
424 : : /* Find PV (in VG) */
425 [ # # ]: 0 : if (!(pv = find_pv_by_name(cmd, pv_name))) {
426 : 0 : stack;
427 : 0 : return EINVALID_CMD_LINE;
428 : : }
429 : :
430 [ # # ]: 0 : if (arg_count(cmd, name_ARG)) {
431 [ # # ]: 0 : if (!(lv_name = _extract_lvname(cmd, pv_vg_name(pv),
432 : : arg_value(cmd, name_ARG)))) {
433 : 0 : stack;
434 : 0 : return EINVALID_CMD_LINE;
435 : : }
436 : :
437 [ # # ]: 0 : if (!validate_name(lv_name)) {
438 : 0 : log_error("Logical volume name %s is invalid", lv_name);
439 : 0 : return EINVALID_CMD_LINE;
440 : : }
441 : : }
442 : :
443 : : /* Read VG */
444 : 0 : log_verbose("Finding volume group \"%s\"", pv_vg_name(pv));
445 : :
446 : 0 : vg = _get_vg(cmd, pv_vg_name(pv));
447 [ # # ]: 0 : if (vg_read_error(vg)) {
448 : 0 : vg_release(vg);
449 : 0 : stack;
450 : 0 : return ECMD_FAILED;
451 : : }
452 : :
453 : 0 : exclusive = _pvmove_is_exclusive(cmd, vg);
454 : :
455 [ # # ]: 0 : if ((lv_mirr = find_pvmove_lv(vg, pv_dev(pv), PVMOVE))) {
456 : 0 : log_print("Detected pvmove in progress for %s", pv_name);
457 [ # # # # ]: 0 : if (argc || lv_name)
458 : 0 : log_error("Ignoring remaining command line arguments");
459 : :
460 [ # # ]: 0 : if (!(lvs_changed = lvs_using_lv(cmd, vg, lv_mirr))) {
461 : 0 : log_error("ABORTING: Failed to generate list of moving LVs");
462 : 0 : goto out;
463 : : }
464 : :
465 : : /* Ensure mirror LV is active */
466 [ # # ]: 0 : if (!_activate_lv(cmd, lv_mirr, exclusive)) {
467 : 0 : log_error("ABORTING: Temporary mirror activation failed.");
468 : 0 : goto out;
469 : : }
470 : :
471 : 0 : first_time = 0;
472 : : } else {
473 : : /* Determine PE ranges to be moved */
474 [ # # ]: 0 : if (!(source_pvl = create_pv_list(cmd->mem, vg, 1,
475 : : &pv_name_arg, 0)))
476 : 0 : goto_out;
477 : :
478 : 0 : alloc = arg_uint_value(cmd, alloc_ARG, ALLOC_INHERIT);
479 [ # # ]: 0 : if (alloc == ALLOC_INHERIT)
480 : 0 : alloc = vg->alloc;
481 : :
482 : : /* Get PVs we can use for allocation */
483 [ # # ]: 0 : if (!(allocatable_pvs = _get_allocatable_pvs(cmd, argc, argv,
484 : : vg, pv, alloc)))
485 : 0 : goto_out;
486 : :
487 [ # # ]: 0 : if (!archive(vg))
488 : 0 : goto_out;
489 : :
490 [ # # ]: 0 : if (!(lv_mirr = _set_up_pvmove_lv(cmd, vg, source_pvl, lv_name,
491 : : allocatable_pvs, alloc,
492 : : &lvs_changed)))
493 : 0 : goto_out;
494 : : }
495 : :
496 : : /* Lock lvs_changed and activate (with old metadata) */
497 [ # # ]: 0 : if (!activate_lvs(cmd, lvs_changed, exclusive))
498 : 0 : goto_out;
499 : :
500 : : /* FIXME Presence of a mirror once set PVMOVE - now remove associated logic */
501 : : /* init_pvmove(1); */
502 : : /* vg->status |= PVMOVE; */
503 : :
504 [ # # ]: 0 : if (first_time) {
505 [ # # ]: 0 : if (!_update_metadata
506 : : (cmd, vg, lv_mirr, lvs_changed, PVMOVE_FIRST_TIME))
507 : 0 : goto_out;
508 : : }
509 : :
510 : : /* LVs are all in status LOCKED */
511 : 0 : r = ECMD_PROCESSED;
512 : : out:
513 : 0 : unlock_and_release_vg(cmd, vg, pv_vg_name(pv));
514 : 0 : return r;
515 : : }
516 : :
517 : 0 : static int _finish_pvmove(struct cmd_context *cmd, struct volume_group *vg,
518 : : struct logical_volume *lv_mirr,
519 : : struct dm_list *lvs_changed)
520 : : {
521 : 0 : int r = 1;
522 : :
523 [ # # ]: 0 : if (!_detach_pvmove_mirror(cmd, lv_mirr)) {
524 : 0 : log_error("ABORTING: Removal of temporary mirror failed");
525 : 0 : return 0;
526 : : }
527 : :
528 : : /* Store metadata without dependencies on mirror segments */
529 [ # # ]: 0 : if (!vg_write(vg)) {
530 : 0 : log_error("ABORTING: Failed to write new data locations "
531 : : "to disk.");
532 : 0 : return 0;
533 : : }
534 : :
535 : : /* Suspend LVs changed */
536 [ # # ]: 0 : if (!suspend_lvs(cmd, lvs_changed)) {
537 : 0 : log_error("Locking LVs to remove temporary mirror failed");
538 : 0 : r = 0;
539 : : }
540 : :
541 : : /* Suspend mirror LV to flush pending I/O */
542 [ # # ][ # # ]: 0 : if (!suspend_lv(cmd, lv_mirr)) {
[ # # ]
543 : 0 : log_error("Suspension of temporary mirror LV failed");
544 : 0 : r = 0;
545 : : }
546 : :
547 : : /* Store metadata without dependencies on mirror segments */
548 [ # # ]: 0 : if (!vg_commit(vg)) {
549 : 0 : log_error("ABORTING: Failed to write new data locations "
550 : : "to disk.");
551 : 0 : vg_revert(vg);
552 [ # # # # ]: 0 : if (!resume_lv(cmd, lv_mirr))
[ # # ]
553 : 0 : stack;
554 [ # # ]: 0 : if (!resume_lvs(cmd, lvs_changed))
555 : 0 : stack;
556 : 0 : return 0;
557 : : }
558 : :
559 : : /* Release mirror LV. (No pending I/O because it's been suspended.) */
560 [ # # ][ # # ]: 0 : if (!resume_lv(cmd, lv_mirr)) {
[ # # ]
561 : 0 : log_error("Unable to reactivate logical volume \"%s\"",
562 : : lv_mirr->name);
563 : 0 : r = 0;
564 : : }
565 : :
566 : : /* Unsuspend LVs */
567 [ # # ]: 0 : if (!resume_lvs(cmd, lvs_changed))
568 : 0 : stack;
569 : :
570 : : /* Deactivate mirror LV */
571 [ # # ][ # # ]: 0 : if (!deactivate_lv(cmd, lv_mirr)) {
[ # # ]
572 : 0 : log_error("ABORTING: Unable to deactivate temporary logical "
573 : : "volume \"%s\"", lv_mirr->name);
574 : 0 : r = 0;
575 : : }
576 : :
577 : 0 : log_verbose("Removing temporary pvmove LV");
578 [ # # ]: 0 : if (!lv_remove(lv_mirr)) {
579 : 0 : log_error("ABORTING: Removal of temporary pvmove LV failed");
580 : 0 : return 0;
581 : : }
582 : :
583 : : /* Store it on disks */
584 : 0 : log_verbose("Writing out final volume group after pvmove");
585 [ # # # # ]: 0 : if (!vg_write(vg) || !vg_commit(vg)) {
586 : 0 : log_error("ABORTING: Failed to write new data locations "
587 : : "to disk.");
588 : 0 : return 0;
589 : : }
590 : :
591 : : /* FIXME backup positioning */
592 : 0 : backup(vg);
593 : :
594 : 0 : return r;
595 : : }
596 : :
597 : 0 : static struct volume_group *_get_move_vg(struct cmd_context *cmd,
598 : : const char *name,
599 : : const char *uuid __attribute((unused)))
600 : : {
601 : : struct physical_volume *pv;
602 : :
603 : : /* Reread all metadata in case it got changed */
604 [ # # ]: 0 : if (!(pv = find_pv_by_name(cmd, name))) {
605 : 0 : log_error("ABORTING: Can't reread PV %s", name);
606 : : /* What more could we do here? */
607 : 0 : return NULL;
608 : : }
609 : :
610 : 0 : return _get_vg(cmd, pv_vg_name(pv));
611 : : }
612 : :
613 : : static struct poll_functions _pvmove_fns = {
614 : : .get_copy_name_from_lv = get_pvmove_pvname_from_lv_mirr,
615 : : .get_copy_vg = _get_move_vg,
616 : : .get_copy_lv = find_pvmove_lv_from_pvname,
617 : : .poll_progress = poll_mirror_progress,
618 : : .update_metadata = _update_metadata,
619 : : .finish_copy = _finish_pvmove,
620 : : };
621 : :
622 : 0 : int pvmove_poll(struct cmd_context *cmd, const char *pv_name,
623 : : unsigned background)
624 : : {
625 [ # # ]: 0 : if (test_mode())
626 : 0 : return ECMD_PROCESSED;
627 : :
628 : 0 : return poll_daemon(cmd, pv_name, NULL, background, PVMOVE, &_pvmove_fns,
629 : : "Moved");
630 : : }
631 : :
632 : 0 : int pvmove(struct cmd_context *cmd, int argc, char **argv)
633 : : {
634 : 0 : char *pv_name = NULL;
635 : : char *colon;
636 : : int ret;
637 : :
638 : : /* dm raid1 target must be present in every case */
639 [ # # ]: 0 : if (!_pvmove_target_present(cmd, 0)) {
640 : 0 : log_error("Required device-mapper target(s) not "
641 : : "detected in your kernel");
642 : 0 : return ECMD_FAILED;
643 : : }
644 : :
645 [ # # ]: 0 : if (argc) {
646 : 0 : pv_name = argv[0];
647 : :
648 : : /* Drop any PE lists from PV name */
649 [ # # ]: 0 : if ((colon = strchr(pv_name, ':'))) {
650 [ # # ]: 0 : if (!(pv_name = dm_pool_strndup(cmd->mem, pv_name,
651 : 0 : (unsigned) (colon -
652 : : pv_name)))) {
653 : 0 : log_error("Failed to clone PV name");
654 : 0 : return ECMD_FAILED;
655 : : }
656 : : }
657 : :
658 [ # # # # ]: 0 : if (!arg_count(cmd, abort_ARG) &&
659 : 0 : (ret = _set_up_pvmove(cmd, pv_name, argc, argv)) !=
660 : : ECMD_PROCESSED) {
661 : 0 : stack;
662 : 0 : return ret;
663 : : }
664 : : }
665 : :
666 : 0 : return pvmove_poll(cmd, pv_name, arg_is_set(cmd, background_ARG));
667 : : }
|