~brightbox/ubuntu/raring/lvm2/fix-for-1076304

« back to all changes in this revision

Viewing changes to tools/vgsplit.c

  • Committer: Bazaar Package Importer
  • Author(s): James Westby
  • Date: 2008-07-01 16:39:18 UTC
  • mto: This revision was merged to the branch mainline in revision 35.
  • Revision ID: james.westby@ubuntu.com-20080701163918-lzcg5lpcdyivgo9v
Tags: upstream-2.02.39
ImportĀ upstreamĀ versionĀ 2.02.39

Show diffs side-by-side

added added

removed removed

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