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