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