]>
Commit | Line | Data |
---|---|---|
fbbe942c | 1 | /* |
67cdbd7e | 2 | * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. |
2c3093af | 3 | * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. |
fbbe942c | 4 | * |
6606c3ae | 5 | * This file is part of LVM2. |
fbbe942c | 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. |
fbbe942c | 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 | |
fbbe942c AK |
14 | */ |
15 | ||
16 | #include "tools.h" | |
17 | ||
072893aa AK |
18 | /* FIXME Why not (lv->vg == vg) ? */ |
19 | static int _lv_is_in_vg(struct volume_group *vg, struct logical_volume *lv) | |
20 | { | |
21 | struct lv_list *lvl; | |
22 | ||
2c44337b | 23 | dm_list_iterate_items(lvl, &vg->lvs) |
072893aa AK |
24 | if (lv == lvl->lv) |
25 | return 1; | |
26 | ||
27 | return 0; | |
28 | } | |
29 | ||
c5421d15 | 30 | static int _move_one_lv(struct volume_group *vg_from, |
3a370b73 | 31 | struct volume_group *vg_to, |
2c44337b | 32 | struct dm_list *lvh) |
3998882f | 33 | { |
2c44337b | 34 | struct logical_volume *lv = dm_list_item(lvh, struct lv_list)->lv; |
3998882f | 35 | |
2c44337b | 36 | dm_list_move(&vg_to->lvs, lvh); |
ebfe96ca | 37 | lv->vg = vg_to; |
2c3093af | 38 | |
c5421d15 DW |
39 | if (lv_is_active(lv)) { |
40 | log_error("Logical volume \"%s\" must be inactive", lv->name); | |
41 | return 0; | |
42 | } | |
43 | ||
c5421d15 | 44 | return 1; |
d60f341d | 45 | } |
072893aa | 46 | |
fbbe942c AK |
47 | static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to) |
48 | { | |
2c44337b | 49 | struct dm_list *lvh, *lvht; |
fbbe942c | 50 | struct logical_volume *lv; |
5a52dca9 | 51 | struct lv_segment *seg; |
fbbe942c AK |
52 | struct physical_volume *pv; |
53 | struct volume_group *vg_with; | |
72b2cb61 | 54 | unsigned s; |
fbbe942c | 55 | |
2c44337b AK |
56 | dm_list_iterate_safe(lvh, lvht, &vg_from->lvs) { |
57 | lv = dm_list_item(lvh, struct lv_list)->lv; | |
fbbe942c | 58 | |
072893aa AK |
59 | if ((lv->status & SNAPSHOT)) |
60 | continue; | |
61 | ||
ce4c3310 AK |
62 | if ((lv->status & MIRRORED)) |
63 | continue; | |
64 | ||
fbbe942c AK |
65 | /* Ensure all the PVs used by this LV remain in the same */ |
66 | /* VG as each other */ | |
67 | vg_with = NULL; | |
2c44337b | 68 | dm_list_iterate_items(seg, &lv->segments) { |
b8c919b4 AK |
69 | for (s = 0; s < seg->area_count; s++) { |
70 | /* FIXME Check AREA_LV too */ | |
60f13f01 | 71 | if (seg_type(seg, s) != AREA_PV) |
b8c919b4 AK |
72 | continue; |
73 | ||
60f13f01 | 74 | pv = seg_pv(seg, s); |
fbbe942c | 75 | if (vg_with) { |
a421f743 | 76 | if (!pv_is_in_vg(vg_with, pv)) { |
e62436fc AK |
77 | log_error("Can't split Logical " |
78 | "Volume %s between " | |
79 | "two Volume Groups", | |
fbbe942c AK |
80 | lv->name); |
81 | return 0; | |
82 | } | |
83 | continue; | |
84 | } | |
85 | ||
a421f743 | 86 | if (pv_is_in_vg(vg_from, pv)) { |
fbbe942c AK |
87 | vg_with = vg_from; |
88 | continue; | |
89 | } | |
a421f743 | 90 | if (pv_is_in_vg(vg_to, pv)) { |
fbbe942c AK |
91 | vg_with = vg_to; |
92 | continue; | |
93 | } | |
94 | log_error("Physical Volume %s not found", | |
1b8de4cb | 95 | pv_dev_name(pv)); |
fbbe942c AK |
96 | return 0; |
97 | } | |
fbbe942c | 98 | |
072893aa | 99 | } |
2c3093af | 100 | |
fbbe942c AK |
101 | if (vg_with == vg_from) |
102 | continue; | |
103 | ||
104 | /* Move this LV */ | |
c5421d15 | 105 | if (!_move_one_lv(vg_from, vg_to, lvh)) |
082628eb | 106 | return_0; |
fbbe942c AK |
107 | } |
108 | ||
b8c919b4 AK |
109 | /* FIXME Ensure no LVs contain segs pointing at LVs in the other VG */ |
110 | ||
fbbe942c AK |
111 | return 1; |
112 | } | |
113 | ||
eec663aa DW |
114 | /* |
115 | * Move the hidden / internal "snapshotN" LVs.from 'vg_from' to 'vg_to'. | |
116 | */ | |
072893aa AK |
117 | static int _move_snapshots(struct volume_group *vg_from, |
118 | struct volume_group *vg_to) | |
fbbe942c | 119 | { |
2c44337b | 120 | struct dm_list *lvh, *lvht; |
072893aa AK |
121 | struct logical_volume *lv; |
122 | struct lv_segment *seg; | |
123 | int cow_from = 0; | |
124 | int origin_from = 0; | |
fbbe942c | 125 | |
2c44337b AK |
126 | dm_list_iterate_safe(lvh, lvht, &vg_from->lvs) { |
127 | lv = dm_list_item(lvh, struct lv_list)->lv; | |
fbbe942c | 128 | |
072893aa AK |
129 | if (!(lv->status & SNAPSHOT)) |
130 | continue; | |
fbbe942c | 131 | |
2c44337b | 132 | dm_list_iterate_items(seg, &lv->segments) { |
072893aa AK |
133 | cow_from = _lv_is_in_vg(vg_from, seg->cow); |
134 | origin_from = _lv_is_in_vg(vg_from, seg->origin); | |
b3b0f199 MB |
135 | |
136 | if (cow_from && origin_from) | |
137 | continue; | |
138 | if ((!cow_from && origin_from) || | |
139 | (cow_from && !origin_from)) { | |
140 | log_error("Can't split snapshot %s between" | |
141 | " two Volume Groups", seg->cow->name); | |
142 | return 0; | |
143 | } | |
072893aa | 144 | |
eec663aa DW |
145 | /* |
146 | * At this point, the cow and origin should already be | |
147 | * in vg_to. | |
148 | */ | |
149 | if (_lv_is_in_vg(vg_to, seg->cow) && | |
c5421d15 DW |
150 | _lv_is_in_vg(vg_to, seg->origin)) { |
151 | if (!_move_one_lv(vg_from, vg_to, lvh)) | |
082628eb | 152 | return_0; |
c5421d15 | 153 | } |
eec663aa | 154 | } |
072893aa | 155 | |
fbbe942c AK |
156 | } |
157 | ||
158 | return 1; | |
159 | } | |
160 | ||
ce4c3310 AK |
161 | static int _move_mirrors(struct volume_group *vg_from, |
162 | struct volume_group *vg_to) | |
163 | { | |
2c44337b | 164 | struct dm_list *lvh, *lvht; |
ce4c3310 | 165 | struct logical_volume *lv; |
a3912484 | 166 | struct lv_segment *seg, *log_seg; |
21bc3664 | 167 | unsigned s, seg_in, log_in; |
ce4c3310 | 168 | |
2c44337b AK |
169 | dm_list_iterate_safe(lvh, lvht, &vg_from->lvs) { |
170 | lv = dm_list_item(lvh, struct lv_list)->lv; | |
ce4c3310 AK |
171 | |
172 | if (!(lv->status & MIRRORED)) | |
173 | continue; | |
174 | ||
67cdbd7e | 175 | seg = first_seg(lv); |
ce4c3310 AK |
176 | |
177 | seg_in = 0; | |
21bc3664 AK |
178 | for (s = 0; s < seg->area_count; s++) |
179 | if (_lv_is_in_vg(vg_to, seg_lv(seg, s))) | |
ce4c3310 AK |
180 | seg_in++; |
181 | ||
a3912484 JEB |
182 | log_in = !seg->log_lv; |
183 | if (seg->log_lv) { | |
184 | log_seg = first_seg(seg->log_lv); | |
185 | if (seg_is_mirrored(log_seg)) { | |
186 | log_in = 1; | |
187 | ||
188 | /* Ensure each log dev is in vg_to */ | |
189 | for (s = 0; s < log_seg->area_count; s++) | |
190 | log_in = log_in && | |
191 | _lv_is_in_vg(vg_to, | |
192 | seg_lv(log_seg, s)); | |
193 | } else | |
194 | log_in = _lv_is_in_vg(vg_to, seg->log_lv); | |
195 | } | |
2c3093af | 196 | |
67cdbd7e AK |
197 | if ((seg_in && seg_in < seg->area_count) || |
198 | (seg_in && seg->log_lv && !log_in) || | |
ce4c3310 | 199 | (!seg_in && seg->log_lv && log_in)) { |
b3b0f199 MB |
200 | log_error("Can't split mirror %s between " |
201 | "two Volume Groups", lv->name); | |
ce4c3310 AK |
202 | return 0; |
203 | } | |
204 | ||
c5421d15 DW |
205 | if (seg_in == seg->area_count && log_in) { |
206 | if (!_move_one_lv(vg_from, vg_to, lvh)) | |
082628eb | 207 | return_0; |
c5421d15 | 208 | } |
ce4c3310 AK |
209 | } |
210 | ||
211 | return 1; | |
212 | } | |
213 | ||
501fda80 DW |
214 | /* |
215 | * Create or open the destination of the vgsplit operation. | |
216 | * Returns | |
217 | * - non-NULL: VG handle w/VG lock held | |
218 | * - NULL: no VG lock held | |
219 | */ | |
220 | static struct volume_group *_vgsplit_to(struct cmd_context *cmd, | |
221 | const char *vg_name_to, | |
222 | int *existing_vg) | |
223 | { | |
224 | struct volume_group *vg_to = NULL; | |
225 | ||
226 | log_verbose("Checking for new volume group \"%s\"", vg_name_to); | |
227 | /* | |
228 | * First try to create a new VG. If we cannot create it, | |
229 | * and we get FAILED_EXIST (we will not be holding a lock), | |
230 | * a VG must already exist with this name. We then try to | |
231 | * read the existing VG - the vgsplit will be into an existing VG. | |
232 | * | |
233 | * Otherwise, if the lock was successful, it must be the case that | |
234 | * we obtained a WRITE lock and could not find the vgname in the | |
235 | * system. Thus, the split will be into a new VG. | |
236 | */ | |
237 | vg_to = vg_create(cmd, vg_name_to); | |
238 | if (vg_read_error(vg_to) == FAILED_LOCKING) { | |
239 | log_error("Can't get lock for %s", vg_name_to); | |
077a6755 | 240 | release_vg(vg_to); |
501fda80 DW |
241 | return NULL; |
242 | } | |
243 | if (vg_read_error(vg_to) == FAILED_EXIST) { | |
244 | *existing_vg = 1; | |
077a6755 | 245 | release_vg(vg_to); |
501fda80 DW |
246 | vg_to = vg_read_for_update(cmd, vg_name_to, NULL, 0); |
247 | ||
248 | if (vg_read_error(vg_to)) { | |
077a6755 | 249 | release_vg(vg_to); |
501fda80 DW |
250 | stack; |
251 | return NULL; | |
252 | } | |
253 | ||
254 | } else if (vg_read_error(vg_to) == SUCCESS) { | |
255 | *existing_vg = 0; | |
256 | } | |
257 | return vg_to; | |
258 | } | |
259 | ||
d1c45aa7 DW |
260 | /* |
261 | * Open the source of the vgsplit operation. | |
262 | * Returns | |
263 | * - non-NULL: VG handle w/VG lock held | |
264 | * - NULL: no VG lock held | |
265 | */ | |
266 | static struct volume_group *_vgsplit_from(struct cmd_context *cmd, | |
267 | const char *vg_name_from) | |
268 | { | |
269 | struct volume_group *vg_from; | |
270 | ||
271 | log_verbose("Checking for volume group \"%s\"", vg_name_from); | |
272 | ||
273 | vg_from = vg_read_for_update(cmd, vg_name_from, NULL, 0); | |
274 | if (vg_read_error(vg_from)) { | |
077a6755 | 275 | release_vg(vg_from); |
d1c45aa7 DW |
276 | return NULL; |
277 | } | |
278 | return vg_from; | |
279 | } | |
280 | ||
1ce224d1 DW |
281 | /* |
282 | * Has the user given an option related to a new vg as the split destination? | |
283 | */ | |
284 | static int new_vg_option_specified(struct cmd_context *cmd) | |
285 | { | |
286 | return(arg_count(cmd, clustered_ARG) || | |
287 | arg_count(cmd, alloc_ARG) || | |
288 | arg_count(cmd, maxphysicalvolumes_ARG) || | |
458a107e DW |
289 | arg_count(cmd, maxlogicalvolumes_ARG) || |
290 | arg_count(cmd, vgmetadatacopies_ARG)); | |
1ce224d1 DW |
291 | } |
292 | ||
fbbe942c AK |
293 | int vgsplit(struct cmd_context *cmd, int argc, char **argv) |
294 | { | |
8868a4ff DW |
295 | struct vgcreate_params vp_new; |
296 | struct vgcreate_params vp_def; | |
aec21154 | 297 | const char *vg_name_from, *vg_name_to; |
043b1362 | 298 | struct volume_group *vg_to = NULL, *vg_from = NULL; |
fbbe942c | 299 | int opt; |
37093b1d | 300 | int existing_vg = 0; |
043b1362 | 301 | int r = ECMD_FAILED; |
85f5392e | 302 | const char *lv_name; |
ab2d981a | 303 | int lock_vg_from_first = 1; |
fbbe942c | 304 | |
85f5392e DW |
305 | if ((arg_count(cmd, name_ARG) + argc) < 3) { |
306 | log_error("Existing VG, new VG and either physical volumes " | |
307 | "or logical volume required."); | |
fbbe942c AK |
308 | return EINVALID_CMD_LINE; |
309 | } | |
310 | ||
85f5392e DW |
311 | if (arg_count(cmd, name_ARG) && (argc > 2)) { |
312 | log_error("A logical volume name cannot be given with " | |
313 | "physical volumes."); | |
314 | return ECMD_FAILED; | |
315 | } | |
316 | ||
317 | if (arg_count(cmd, name_ARG)) | |
318 | lv_name = arg_value(cmd, name_ARG); | |
319 | else | |
320 | lv_name = NULL; | |
321 | ||
b9b26011 AK |
322 | vg_name_from = skip_dev_dir(cmd, argv[0], NULL); |
323 | vg_name_to = skip_dev_dir(cmd, argv[1], NULL); | |
fbbe942c AK |
324 | argc -= 2; |
325 | argv += 2; | |
326 | ||
327 | if (!strcmp(vg_name_to, vg_name_from)) { | |
328 | log_error("Duplicate volume group name \"%s\"", vg_name_from); | |
329 | return ECMD_FAILED; | |
330 | } | |
331 | ||
ae4ca998 DW |
332 | if (strcmp(vg_name_to, vg_name_from) < 0) |
333 | lock_vg_from_first = 0; | |
334 | ||
eb7c87e9 DW |
335 | if (lock_vg_from_first) { |
336 | vg_from = _vgsplit_from(cmd, vg_name_from); | |
651ff9b3 AK |
337 | if (!vg_from) { |
338 | stack; | |
eb7c87e9 | 339 | return ECMD_FAILED; |
651ff9b3 | 340 | } |
eb7c87e9 DW |
341 | /* |
342 | * Set metadata format of original VG. | |
343 | * NOTE: We must set the format before calling vg_create() | |
344 | * since vg_create() calls the per-format constructor. | |
345 | */ | |
346 | cmd->fmt = vg_from->fid->fmt; | |
347 | ||
348 | vg_to = _vgsplit_to(cmd, vg_name_to, &existing_vg); | |
349 | if (!vg_to) { | |
077a6755 | 350 | unlock_and_release_vg(cmd, vg_from, vg_name_from); |
651ff9b3 | 351 | stack; |
eb7c87e9 DW |
352 | return ECMD_FAILED; |
353 | } | |
354 | } else { | |
355 | vg_to = _vgsplit_to(cmd, vg_name_to, &existing_vg); | |
651ff9b3 AK |
356 | if (!vg_to) { |
357 | stack; | |
eb7c87e9 | 358 | return ECMD_FAILED; |
651ff9b3 | 359 | } |
eb7c87e9 DW |
360 | vg_from = _vgsplit_from(cmd, vg_name_from); |
361 | if (!vg_from) { | |
077a6755 | 362 | unlock_and_release_vg(cmd, vg_to, vg_name_to); |
651ff9b3 | 363 | stack; |
eb7c87e9 DW |
364 | return ECMD_FAILED; |
365 | } | |
10a27bdf | 366 | |
eb7c87e9 DW |
367 | if (cmd->fmt != vg_from->fid->fmt) { |
368 | /* In this case we don't know the vg_from->fid->fmt */ | |
369 | log_error("Unable to set new VG metadata type based on " | |
370 | "source VG format - use -M option."); | |
371 | goto bad; | |
372 | } | |
cbfbc676 | 373 | } |
eb7c87e9 | 374 | |
5bad8ac8 | 375 | if (existing_vg) { |
1ce224d1 DW |
376 | if (new_vg_option_specified(cmd)) { |
377 | log_error("Volume group \"%s\" exists, but new VG " | |
378 | "option specified", vg_name_to); | |
651ff9b3 | 379 | goto bad; |
1ce224d1 | 380 | } |
d865615e | 381 | if (!vgs_are_compatible(cmd, vg_from,vg_to)) |
3a370b73 | 382 | goto_bad; |
5bad8ac8 | 383 | } else { |
c6ea6bf5 | 384 | vgcreate_params_set_defaults(&vp_def, vg_from); |
2a924b3e DW |
385 | vp_def.vg_name = vg_name_to; |
386 | if (vgcreate_params_set_from_args(cmd, &vp_new, &vp_def)) { | |
043b1362 | 387 | r = EINVALID_CMD_LINE; |
651ff9b3 | 388 | goto_bad; |
c1f2ce39 | 389 | } |
b8daca85 | 390 | |
a42efe6b | 391 | if (vgcreate_params_validate(cmd, &vp_new)) { |
043b1362 | 392 | r = EINVALID_CMD_LINE; |
651ff9b3 | 393 | goto_bad; |
c1f2ce39 | 394 | } |
b8daca85 | 395 | |
10a27bdf DW |
396 | if (!vg_set_extent_size(vg_to, vp_new.extent_size) || |
397 | !vg_set_max_lv(vg_to, vp_new.max_lv) || | |
398 | !vg_set_max_pv(vg_to, vp_new.max_pv) || | |
fc7ad9d4 | 399 | !vg_set_alloc_policy(vg_to, vp_new.alloc) || |
458a107e | 400 | !vg_set_clustered(vg_to, vp_new.clustered) || |
12eadbab | 401 | !vg_set_mda_copies(vg_to, vp_new.vgmetadatacopies)) |
3a370b73 | 402 | goto_bad; |
3853d11f | 403 | } |
805dad59 | 404 | |
fbbe942c AK |
405 | /* Archive vg_from before changing it */ |
406 | if (!archive(vg_from)) | |
3a370b73 | 407 | goto_bad; |
fbbe942c AK |
408 | |
409 | /* Move PVs across to new structure */ | |
410 | for (opt = 0; opt < argc; opt++) { | |
e59e2f7c | 411 | dm_unescape_colons_and_at_signs(argv[opt], NULL, NULL); |
6452d4ae | 412 | if (!move_pv(vg_from, vg_to, argv[opt])) |
3a370b73 | 413 | goto_bad; |
85f5392e | 414 | } |
a8bffd6c | 415 | |
85f5392e | 416 | /* If an LV given on the cmdline, move used_by PVs */ |
6452d4ae | 417 | if (lv_name && !move_pvs_used_by_lv(vg_from, vg_to, lv_name)) |
3a370b73 | 418 | goto_bad; |
fbbe942c AK |
419 | |
420 | /* Move required LVs across, checking consistency */ | |
421 | if (!(_move_lvs(vg_from, vg_to))) | |
3a370b73 | 422 | goto_bad; |
fbbe942c | 423 | |
984abde1 | 424 | /* FIXME Separate the 'move' from the 'validation' to fix dev stacks */ |
ce4c3310 AK |
425 | /* Move required mirrors across */ |
426 | if (!(_move_mirrors(vg_from, vg_to))) | |
3a370b73 | 427 | goto_bad; |
984abde1 AK |
428 | |
429 | /* Move required snapshots across */ | |
430 | if (!(_move_snapshots(vg_from, vg_to))) | |
431 | goto_bad; | |
ce4c3310 | 432 | |
851002b8 | 433 | /* Split metadata areas and check if both vgs have at least one area */ |
b9567c95 | 434 | if (!(vg_split_mdas(cmd, vg_from, vg_to)) && vg_from->pv_count) { |
851002b8 | 435 | log_error("Cannot split: Nowhere to store metadata for new Volume Group"); |
651ff9b3 | 436 | goto bad; |
851002b8 MB |
437 | } |
438 | ||
439 | /* Set proper name for all PVs in new VG */ | |
440 | if (!vg_rename(cmd, vg_to, vg_name_to)) | |
3a370b73 | 441 | goto_bad; |
5a52dca9 | 442 | |
fbbe942c AK |
443 | /* store it on disks */ |
444 | log_verbose("Writing out updated volume groups"); | |
445 | ||
cbfbc676 DW |
446 | /* |
447 | * First, write out the new VG as EXPORTED. We do this first in case | |
448 | * there is a crash - we will still have the new VG information, in an | |
449 | * exported state. Recovery after this point would be removal of the | |
450 | * new VG and redoing the vgsplit. | |
451 | * FIXME: recover automatically or instruct the user? | |
452 | */ | |
fbbe942c AK |
453 | vg_to->status |= EXPORTED_VG; |
454 | ||
455 | if (!archive(vg_to)) | |
3a370b73 | 456 | goto_bad; |
fbbe942c | 457 | |
914c9723 | 458 | if (!vg_write(vg_to) || !vg_commit(vg_to)) |
3a370b73 | 459 | goto_bad; |
fbbe942c AK |
460 | |
461 | backup(vg_to); | |
462 | ||
cbfbc676 DW |
463 | /* |
464 | * Next, write out the updated old VG. If we crash after this point, | |
465 | * recovery is a vgimport on the new VG. | |
3a370b73 | 466 | * FIXME: recover automatically or instruct the user? |
cbfbc676 | 467 | */ |
b9567c95 MB |
468 | if (vg_from->pv_count) { |
469 | if (!vg_write(vg_from) || !vg_commit(vg_from)) | |
3a370b73 | 470 | goto_bad; |
fbbe942c | 471 | |
b9567c95 MB |
472 | backup(vg_from); |
473 | } | |
fbbe942c | 474 | |
cbfbc676 DW |
475 | /* |
476 | * Finally, remove the EXPORTED flag from the new VG and write it out. | |
477 | */ | |
043b1362 | 478 | if (!test_mode()) { |
077a6755 | 479 | release_vg(vg_to); |
819f14ea DW |
480 | vg_to = vg_read_for_update(cmd, vg_name_to, NULL, |
481 | READ_ALLOW_EXPORTED); | |
482 | if (vg_read_error(vg_to)) { | |
483 | log_error("Volume group \"%s\" became inconsistent: " | |
484 | "please fix manually", vg_name_to); | |
651ff9b3 | 485 | goto bad; |
043b1362 | 486 | } |
5a52dca9 AK |
487 | } |
488 | ||
fbbe942c AK |
489 | vg_to->status &= ~EXPORTED_VG; |
490 | ||
d0afc2c8 | 491 | if (!vg_write(vg_to) || !vg_commit(vg_to)) |
3a370b73 | 492 | goto_bad; |
fbbe942c AK |
493 | |
494 | backup(vg_to); | |
495 | ||
c1f2ce39 DW |
496 | log_print("%s volume group \"%s\" successfully split from \"%s\"", |
497 | existing_vg ? "Existing" : "New", | |
fbbe942c | 498 | vg_to->name, vg_from->name); |
fbbe942c | 499 | |
043b1362 MB |
500 | r = ECMD_PROCESSED; |
501 | ||
502 | bad: | |
91d865ca | 503 | /* |
919ab56b AK |
504 | * vg_to references elements moved from vg_from |
505 | * so vg_to has to be freed first. | |
91d865ca | 506 | */ |
077a6755 ZK |
507 | unlock_and_release_vg(cmd, vg_to, vg_name_to); |
508 | unlock_and_release_vg(cmd, vg_from, vg_name_from); | |
91d865ca | 509 | |
043b1362 | 510 | return r; |
fbbe942c | 511 | } |