source: MondoRescue/devel/mr/lib/MondoRescue/LVM.pm

Last change on this file was 3108, checked in by Bruno Cornec, 11 years ago

r5244@localhost: bruno | 2013-04-29 00:16:57 +0200

  • Minor improvements for devel version of mondorescue
File size: 18.7 KB
Line 
1#!/usr/bin/perl -w
2#
3# Subroutines related to LVM brought by the MondoRescue project
4#
5# $Id$
6#
7# Copyright B. Cornec 2008-2010
8# Provided under the GPL v2
9
10package MondoRescue::LVM;
11
12use strict 'vars';
13use Data::Dumper;
14use English;
15use lib qw (lib);
16use ProjectBuilder::Base;
17use ProjectBuilder::Conf;
18use MondoRescue::Base;
19
20# Inherit from the "Exporter" module which handles exporting functions.
21
22use Exporter;
23
24# Export, by default, all the functions into the namespace of
25# any code which uses this module.
26
27our @ISA = qw(Exporter);
28our @EXPORT = qw(mr_lvm_check mr_lvm_get_conf mr_lvm_read_conf mr_lvm_write_conf mr_lvm_edit_conf mr_lvm_apply_from_conf);
29
30=pod
31
32=head1 NAME
33
34MondoRescue::LVM, part of the mondorescue.org
35
36=head1 DESCRIPTION
37
38This modules provides low level functions for LVM support in the Mondorescue project
39
40=head1 USAGE
41
42=over 4
43
44=item B<mr_lvm_check>
45
46This function checks the usage of LVM and gets the version used
47It returns 2 parameters, the LVM version, and the lvm command to use if needed
48The LVM version could be undef, 0 (no LVM), 1 or 2 at the moment, or further not yet supported version
49It potentially takes one parameter, the LVM version, already known, in which case it easily deduced the LVM command.
50If LVM version is undefined then no LVM Handling should be done.
51It has to run on on a system where LVM is activated to return useful results so typically on the system to backup
52
53=cut
54
55sub mr_lvm_check {
56
57my $lvmver = shift;
58
59# Get params from the conf file
60my ($lvmds_t,$lvmproc_t,$lvmcmd_t,$lvmpath_t) = pb_conf_get("mr_cmd_lvmdiskscan","mr_proc_lvm","mr_cmd_lvm","mr_path_lvm");
61my $lvmds = $lvmds_t->{$ENV{PBPROJ}};
62my $lvmproc = $lvmproc_t->{$ENV{PBPROJ}};
63my $lvmcmd = $lvmcmd_t->{$ENV{PBPROJ}};
64my $lvmpath = $lvmpath_t->{$ENV{PBPROJ}};
65
66# That file is not mandatory anymore
67if (not defined $lvmver) {
68 if (! -x $lvmproc) {
69 pb_log(1,"$lvmproc doesn't exist\n");
70 } else {
71 # Check LVM volumes presence
72 pb_log(2,"Checking with $lvmproc\n");
73 open(LVM,$lvmproc) || mr_exit(-1,"Unable to open $lvmproc");
74 while (<LVM>) {
75 if (/0 VGs 0 PVs 0 LVs/) {
76 pb_log(1,"No LVM volumes found in $lvmproc\n");
77 return(0,undef);
78 }
79 }
80 close(LVM);
81 }
82}
83
84# Check LVM version
85if (not defined $lvmver) {
86 pb_log(2,"LVM version value is not known\n");
87 if (-x $lvmds) {
88 pb_log(2,"Checking with $lvmds\n");
89 open(LVM,"$lvmds --help 2>&1 |") || mr_exit(-1,"Unable to execute $lvmds");
90 while (<LVM>) {
91 if (/Logical Volume Manager/ || /LVM version:/) {
92 $lvmver = $_;
93 chomp($lvmver);
94 $lvmver =~ s/:([0-9])\..*/$1/;
95 }
96 }
97 close(LVM);
98 pb_log(2,"Found a LVM version of $lvmver with $lvmds --help\n") if (defined $lvmver);
99 }
100}
101
102if (not defined $lvmver) {
103 pb_log(2,"LVM version value is still not known\n");
104 if (-x $lvmcmd) {
105 pb_log(2,"Checking with $lvmcmd\n");
106 open(LVM,"$lvmcmd version |") || mr_exit(-1,"Unable to execute $lvmcmd");
107 while (<LVM>) {
108 if (/LVM version/) {
109 $lvmver = $_;
110 chomp($lvmver);
111 $lvmver =~ s/:([0-9])\..*/$1/;
112 $lvmver =~ s/[\s]*LVM version[:]*[\s]+([0-9])\..*/$1/;
113 }
114 }
115 close(LVM);
116 pb_log(2,"Found a LVM version of $lvmver with $lvmcmd version\n") if (defined $lvmver);
117 }
118}
119
120if (not defined $lvmver) {
121 # Still not found
122 mr_log(0,"Unable to determine LVM version.\nIf you think this is wrong, please report to the dev team with the result of the commands:\n$lvmds --help and $lvmcmd version\n");
123} elsif ($lvmver == 1) {
124 $lvmcmd = "$lvmpath";
125} elsif ($lvmver == 2) {
126 $lvmcmd .= " ";
127} else {
128 pb_log(0,"Unknown LVM version $lvmver\n");
129}
130# Here $lvmcmd contains a full path name
131pb_log(1,"Found LVM version $lvmver\n");
132return ($lvmver,$lvmcmd);
133
134}
135
136=over 4
137
138=item B<mr_lvm_get_conf>
139
140This function returns 1 parameters, the LVM structure or undef if no LVM
141That LVM structure contains all the information related to the current LVM configuration
142
143=cut
144
145sub mr_lvm_get_conf {
146
147my $lvm = undef;
148
149my ($lvmver,$lvmcmd) = mr_lvm_check();
150return(undef) if ((not defined $lvmver) || ($lvmver == 0));
151
152# Analyze the existing physical volumes
153open(LVM,$lvmcmd."pvs --noheadings --nosuffix --units m --separator : -o pv_name,vg_name,pv_all,pv_fmt,pv_uuid,dev_size,pv_mda_free,pv_mda_size |") || mr_exit(-1,"Unable to execute ".$lvmcmd."pvs");
154while (<LVM>) {
155 s/^[\s]*//;
156
157 my ($pv_name,$vg_name,$pe_start,$pv_size,$pv_free,$pv_used,$pv_attr,$pv_pe_count,$pv_pe_alloc_count,$pv_tags,$pv_mda_count,$pv_uuid,$dev_size,$pv_mda_free,$pv_mda_size) = split(/:/);
158
159=pod
160
161The LVM hash is indexed by VGs, provided by the vg_name attribute of the pvs command
162vg_name - Name of the volume group linked to this PV
163
164=cut
165
166 $lvm->{$vg_name}->{'pvnum'}++;
167
168=pod
169
170The structure contains an array of PVs called pvs and starting at 1, containing the name of the PV as provided by the pv_name attribute of the pvs command
171pv_name - Name of the physical volume PV
172
173=cut
174
175 # Array of PVs for that VG
176 $lvm->{$vg_name}->{'pvs'}->[$lvm->{$vg_name}->{'pvnum'}] = $pv_name;
177
178=pod
179
180All the PV fields from the pvs command are gathered under their PV name (substructure)
181The following names are used:
182
183From pvs -o help
184pe_start - Offset to the start of data on the underlying device.
185pv_size - Size of PV in current units.
186pv_free - Total amount of unallocated space in current units.
187pv_used - Total amount of allocated space in current units.
188pv_attr - Various attributes - see man page.
189pv_pe_count - Total number of Physical Extents.
190pv_pe_alloc_count - Total number of allocated Physical Extents.
191pv_tags - Tags, if any.
192pv_mda_count - Number of metadata areas on this device.
193pv_fmt - Type of metadata.
194pv_uuid - Unique identifier.
195dev_size - Size of underlying device in current units.
196pv_mda_free - Free metadata area space on this device in current units.
197pv_mda_size - Size of smallest metadata area on this device in current units.
198
199=cut
200
201 $lvm->{$vg_name}->{$pv_name}->{'pe_start'} = $pe_start;
202 $lvm->{$vg_name}->{$pv_name}->{'pv_size'} = $pv_size;
203 $lvm->{$vg_name}->{$pv_name}->{'pv_free'} = $pv_free;
204 $lvm->{$vg_name}->{$pv_name}->{'pv_used'} = $pv_used;
205 $lvm->{$vg_name}->{$pv_name}->{'pv_attr'} = $pv_attr;
206 $lvm->{$vg_name}->{$pv_name}->{'pv_pe_count'} = $pv_pe_count;
207 $lvm->{$vg_name}->{$pv_name}->{'pv_pe_alloc_count'} = $pv_pe_alloc_count;
208 $lvm->{$vg_name}->{$pv_name}->{'pv_tags'} = $pv_tags;
209 $lvm->{$vg_name}->{$pv_name}->{'pv_mda_count'} = $pv_mda_count;
210 $lvm->{$vg_name}->{$pv_name}->{'pv_uuid'} = $pv_uuid;
211 $lvm->{$vg_name}->{$pv_name}->{'dev_size'} = $dev_size;
212 $lvm->{$vg_name}->{$pv_name}->{'pv_mda_free'} = $pv_mda_free;
213 $lvm->{$vg_name}->{$pv_name}->{'pv_mda_size'} = $pv_mda_size;
214}
215close(LVM);
216
217# Analyze the existing volume groups
218#open(LVM,$lvmcmd."vgdisplay -c |") || mr_exit(-1,"Unable to execute ".$lvmcmd."vgdisplay -c");
219open(LVM,$lvmcmd."vgs --noheadings --nosuffix --units m --separator : -o vg_all |") || mr_exit(-1,"Unable to execute ".$lvmcmd."vgs");
220while (<LVM>) {
221
222=pod
223
224All the VG fields from the vgs command are gathered under the VG name
225The following names are used:
226
227From vgs -o help
228vg_fmt - Type of metadata.
229vg_uuid - Unique identifier.
230vg_attr - Various attributes - see man page.
231vg_size - Total size of VG in current units.
232vg_free - Total amount of free space in current units.
233vg_sysid - System ID indicating when and where it was created.
234vg_extent_size - Size of Physical Extents in current units.
235vg_extent_count - Total number of Physical Extents.
236vg_free_count - Total number of unallocated Physical Extents.
237max_lv - Maximum number of LVs allowed in VG or 0 if unlimited.
238max_pv - Maximum number of PVs allowed in VG or 0 if unlimited.
239pv_count - Number of PVs.
240lv_count - Number of LVs.
241snap_count - Number of snapshots.
242vg_seqno - Revision number of internal metadata. Incremented whenever it changes.
243vg_tags - Tags, if any.
244vg_mda_count - Number of metadata areas in use by this VG.
245vg_mda_free - Free metadata area space for this VG in current units.
246vg_mda_size - Size of smallest metadata area for this VG in current units.
247
248=cut
249 s/^[\s]*//;
250 my ($vg_fmt,$vg_uuid,$vg_name,$vg_attr,$vg_size,$vg_free,$vg_sysid,$vg_extend_size,$vg_extend_count,$vg_free_count,$max_lv,$max_pv,$pv_count,$lv_count,$snap_count,$vg_seqno,$vg_tags,$vg_mda_count,$vg_mda_free,$vg_mda_size) = split(/:/);
251 $lvm->{$vg_name}->{'vg_fmt'} = $vg_fmt;
252 $lvm->{$vg_name}->{'vg_uuid'} = $vg_uuid;
253 $lvm->{$vg_name}->{'vg_attr'} = $vg_attr;
254 $lvm->{$vg_name}->{'vg_size'} = $vg_size;
255 $lvm->{$vg_name}->{'vg_free'} = $vg_free;
256 $lvm->{$vg_name}->{'vg_sysid'} = $vg_sysid;
257 $lvm->{$vg_name}->{'vg_extend_size'} = $vg_extend_size;
258 $lvm->{$vg_name}->{'vg_extend_count'} = $vg_extend_count;
259 $lvm->{$vg_name}->{'vg_free_count'} = $vg_free_count;
260 $lvm->{$vg_name}->{'max_lv'} = $max_lv;
261 $lvm->{$vg_name}->{'max_pv'} = $max_pv;
262 $lvm->{$vg_name}->{'pv_count'} = $pv_count;
263 $lvm->{$vg_name}->{'lv_count'} = $lv_count;
264 $lvm->{$vg_name}->{'snap_count'} = $snap_count;
265 $lvm->{$vg_name}->{'vg_seqno'} = $vg_seqno;
266 $lvm->{$vg_name}->{'vg_tags'} = $vg_tags;
267 $lvm->{$vg_name}->{'vg_mda_count'} = $vg_mda_count;
268 $lvm->{$vg_name}->{'vg_mda_free'} = $vg_mda_free;
269 $lvm->{$vg_name}->{'vg_mda_size'} = $vg_mda_size;
270}
271close(LVM);
272
273# Analyze the existing logical volumes
274#open(LVM,$lvmcmd."lvdisplay -c |") || mr_exit(-1,"Unable to execute ".$lvmcmd."lvdisplay -c");
275open(LVM,$lvmcmd."lvs --noheadings --nosuffix --units m --separator : -o vg_name,lv_all|") || mr_exit(-1,"Unable to execute ".$lvmcmd."lvs");
276while (<LVM>) {
277 s/^[\s]*//;
278
279=pod
280
281The structure contains an array of LVs called lvs and starting at 1, containing the name of the PV as provided by the pv_name attribute of the pvs command
282
283=cut
284
285 my ($vg_name,$lv_uuid,$lv_name,$lv_attr,$lv_major,$lv_minor,$lv_read_ahead,$lv_kernel_major,$lv_kernel_minor,$lv_kernel_read_ahead,$lv_size,$seg_count,$origin,$origin_size,$snap_percent,$copy_percent,$move_pv,$convert_lv,$lv_tags,$mirror_log,$modules) = split(/:/);
286
287=pod
288
289All the PV fields from the pvs command are gathered under their PV name (substructure)
290The following names are used:
291
292
293 # From lvs -o help
294
295 #vg_name - Name of the related volume group
296 #lv_uuid - Unique identifier.
297 #lv_name - Name. LVs created for internal use are enclosed in brackets.
298 #lv_attr - Various attributes - see man page.
299 #lv_major - Persistent major number or -1 if not persistent.
300 #lv_minor - Persistent minor number or -1 if not persistent.
301 #lv_read_ahead - Read ahead setting in current units.
302 #lv_kernel_major - Currently assigned major number or -1 if LV is not active.
303 #lv_kernel_minor - Currently assigned minor number or -1 if LV is not active.
304 #lv_kernel_read_ahead - Currently-in-use read ahead setting in current units.
305 #lv_size - Size of LV in current units.
306 #seg_count - Number of segments in LV.
307 #origin - For snapshots, the origin device of this LV.
308 #origin_size - For snapshots, the size of the origin device of this LV.
309 #snap_percent - For snapshots, the percentage full if LV is active.
310 #copy_percent - For mirrors and pvmove, current percentage in-sync.
311 #move_pv - For pvmove, Source PV of temporary LV created by pvmove.
312 #convert_lv - For lvconvert, Name of temporary LV created by lvconvert.
313 #lv_tags - Tags, if any.
314 #mirror_log - For mirrors, the LV holding the synchronisation log.
315 #modules - Kernel device-mapper modules required for this LV.
316
317=cut
318
319 # The LVM hash is indexed by VGs
320 $lvm->{$vg_name}->{'lvnum'}++;
321 # That array will start at 1 then
322 # Array of LVs for that VG
323 $lvm->{$vg_name}->{'lvs'}->[$lvm->{$vg_name}->{'lvnum'}] = $lv_name;
324 # All LV fields gathered under the LV name
325 $lvm->{$vg_name}->{$lv_name}->{'lv_uuid'} = $lv_uuid;
326 $lvm->{$vg_name}->{$lv_name}->{'lv_attr'} = $lv_attr;
327 $lvm->{$vg_name}->{$lv_name}->{'lv_major'} = $lv_major;
328 $lvm->{$vg_name}->{$lv_name}->{'lv_minor'} = $lv_minor;
329 $lvm->{$vg_name}->{$lv_name}->{'lv_read_ahead'} = $lv_read_ahead;
330 $lvm->{$vg_name}->{$lv_name}->{'lv_kernel_major'} = $lv_kernel_major;
331 $lvm->{$vg_name}->{$lv_name}->{'lv_kernel_minor'} = $lv_kernel_minor;
332 $lvm->{$vg_name}->{$lv_name}->{'lv_kernel_read_ahead'} = $lv_kernel_read_ahead;
333 $lvm->{$vg_name}->{$lv_name}->{'lv_size'} = $lv_size;
334 $lvm->{$vg_name}->{$lv_name}->{'origin'} = $origin;
335 $lvm->{$vg_name}->{$lv_name}->{'origin_size'} = $origin_size;
336 $lvm->{$vg_name}->{$lv_name}->{'snap_percent'} = $snap_percent;
337 $lvm->{$vg_name}->{$lv_name}->{'copy_percent'} = $copy_percent;
338 $lvm->{$vg_name}->{$lv_name}->{'move_pv'} = $move_pv;
339 $lvm->{$vg_name}->{$lv_name}->{'convert_lv'} = $convert_lv;
340 $lvm->{$vg_name}->{$lv_name}->{'lv_tags'} = $lv_tags;
341 $lvm->{$vg_name}->{$lv_name}->{'mirror_log'} = $mirror_log;
342 $lvm->{$vg_name}->{$lv_name}->{'modules'} = $modules;
343}
344close(LVM);
345return($lvm);
346}
347
348=item B<mr_lvm_analyze>
349
350This function outputs in a file descriptor the LVM analysis done
351It returns 1 parameters, the LVM version or 0 if no LVM
352
353=cut
354
355sub mr_lvm_analyze {
356
357my $OUTPUT = shift;
358
359my ($lvmver,$lvmcmd) = mr_lvm_check();
360my $lvm = mr_lvm_get_conf();
361return(undef) if ($lvmver == 0);
362
363print $OUTPUT "LVM:$lvmver\n";
364
365# Analyze the existing physical volumes
366#open(LVM,$lvmcmd."pvdisplay -c |") || mr_exit(-1,"Unable to execute ".$lvmcmd."pvdisplay -c");
367open(LVM,$lvmcmd."pvs --noheadings --nosuffix --units m --separator : |") || mr_exit(-1,"Unable to execute ".$lvmcmd."pvs");
368while (<LVM>) {
369 s/^[\s]*//;
370 my ($pv,$vg,$foo,$foo2,$size,$foo3) = split(/:/);
371 $lvm->{$vg}->{'pvnum'}++;
372 # that array will start at 1 then
373 $lvm->{$vg}->{'pv'}->[$lvm->{$vg}->{'pvnum'}] = $pv;
374 $lvm->{$vg}->{$pv}->{'size'} = $size;
375 print $OUTPUT "PV:$_";
376}
377close(LVM);
378
379# Analyze the existing volume groups
380#open(LVM,$lvmcmd."vgdisplay -c |") || mr_exit(-1,"Unable to execute ".$lvmcmd."vgdisplay -c");
381open(LVM,$lvmcmd."vgs --noheadings --nosuffix --units m --separator : |") || mr_exit(-1,"Unable to execute ".$lvmcmd."vgs");
382while (<LVM>) {
383 s/^[\s]*//;
384 print $OUTPUT "VG:$_";
385}
386close(LVM);
387
388# Analyze the existing logical volumes
389#open(LVM,$lvmcmd."lvdisplay -c |") || mr_exit(-1,"Unable to execute ".$lvmcmd."lvdisplay -c");
390open(LVM,$lvmcmd."lvs --noheadings --nosuffix --units m --separator : |") || mr_exit(-1,"Unable to execute ".$lvmcmd."lvs");
391while (<LVM>) {
392 s/^[\s]*//;
393 print $OUTPUT "LV:$_";
394}
395close(LVM);
396return($lvm);
397}
398
399
400=over 4
401
402=item B<mr_lvm_prepare>
403
404This function outputs in a file descriptor the LVM setup needed to restore LVM conf
405It returns 1 parameters, the LVM version or 0 if no LVM
406
407=cut
408
409sub mr_lvm_prepare {
410
411my $INPUT = shift;
412my $OUTPUT = shift;
413my $mrmult = shift;
414my $lvmcmd;
415my $lvmver;
416
417# Generate the startup scrit needed to restore LVM conf
418# from what is given on input
419# Multiply by the multiplier given in input or 1 of none
420
421my $firsttime = 0;
422while (<$INPUT>) {
423 if (/^LVM:/) {
424 my $tag;
425 my $foo;
426 ($tag,$lvmver) = split(/:/);
427 ($foo,$lvmcmd) = mr_lvm_check($lvmver);
428
429 print $OUTPUT "# Desactivate Volume Groups\n";
430 print $OUTPUT $lvmcmd."vgchange -an\n";
431 print $OUTPUT "\n";
432
433 } elsif (/^PV:/) {
434 # This is for pvdisplay -c
435 #my ($tag,$pvname,$vgname,$pvsize,$ipvn,$pvstat,$pvna,$lvnum,$pesize,$petot,$pefree,$pelloc) = split(/:/);
436 my ($tag,$pvname,$vgname,$lvmv,$more,$pesize,$pefree) = split(/:/);
437 print $OUTPUT "# Creating Physical Volumes $pvname\n";
438 print $OUTPUT $lvmcmd."pvcreate -ff -y";
439 print $OUTPUT " -s ".$pesize*$mrmult if (defined $pesize);
440 print $OUTPUT " $pvname\n";
441 print $OUTPUT "\n";
442 } elsif (/^VG:/) {
443 # This if for vgdisplay -c
444 #my ($tag,$vgname,$vgaccess,$vgstat,$vgnum,$lvmaxnum,$lvnum,$ocalvinvg,$lvmaxsize,$pvmaxnum,$cnumpv,$anumpv,$vgsize,$pesize,$penum,$pealloc,$pefree,$uuid) = split(/:/);
445 my ($tag,$vgname,$pvnum,$lvnum,$attr,$vgsize,$vgfree) = split(/:/);
446 if ($lvmver < 2) {
447 print $OUTPUT "# Removing device first as LVM v1 doesn't do it\n";
448 print $OUTPUT "rm -Rf /dev/$vgname\n";
449 }
450 #$lvmaxnum = 255 if (($lvmaxnum > 256) or (not defined $lvmaxnum));
451 #$pvmaxnum = 255 if (($pvmaxnum > 256) or (not defined $pvmaxnum));
452 print $OUTPUT "# Create Volume Group $vgname\n";
453 # Pb sur pesize unite ?
454 print $OUTPUT $lvmcmd."vgcreate $vgname ";
455 #print $OUTPUT "-p $pvmaxnum -l $lvmaxnum";
456 #print $OUTPUT " -s ".$pesize."\n" if (defined $pesize);
457 print $OUTPUT "\n";
458
459 } elsif (/^LV:/) {
460 if ($firsttime == 0) {
461 print $OUTPUT "\n";
462 print $OUTPUT "# Activate All Volume Groups\n";
463 print $OUTPUT $lvmcmd."vgchange -ay\n";
464 print $OUTPUT "\n";
465 $firsttime = 1;
466 }
467 my ($tag,$lvname,$vgname,$lvaccess,$lvstat,$lvnum,$oclv,$lvsize,$leinlv,$lealloc,$allocpol,$readahead,$major,$minor) = split(/:/);
468 print $OUTPUT "# Create Logical Volume $lvname\n";
469 print $OUTPUT $lvmcmd."lvcreate -n $lvname -L ".$lvsize*$mrmult;
470 print $OUTPUT " -r $readahead" if (defined $readahead);
471 print $OUTPUT " $vgname\n";
472 #[ "$stripes" ] && output="$output -i $stripes"
473 #[ "$stripesize" ] && output="$output -I $stripesize"
474 }
475}
476
477print $OUTPUT "\n";
478print $OUTPUT "# Scanning again Volume Groups\n";
479print $OUTPUT $lvmcmd."vgscan\n";
480print $OUTPUT "\n";
481
482}
483
484=back
485
486=head1 WEB SITES
487
488The main Web site of the project is available at L<http://www.mondorescue.org/>. Bug reports should be filled using the trac instance of the project at L<http://trac.mondorescue.org/>.
489
490=head1 USER MAILING LIST
491
492The mailing list of the project is available at L<mailto:mondo@lists.sf.net>
493
494=head1 AUTHORS
495
496The Mondorescue.org team L<http://www.mondorescue.org/> lead by Bruno Cornec L<mailto:bruno@mondorescue.org>.
497
498=head1 COPYRIGHT
499
500This module is distributed under the GPL v2.0 license
501described in the file C<COPYING> included with the distribution.
502
503
504=cut
505
5061;
507
Note: See TracBrowser for help on using the repository browser.