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