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