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