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