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