summaryrefslogtreecommitdiffstats
path: root/perl-install/lvm.pm
diff options
context:
space:
mode:
Diffstat (limited to 'perl-install/lvm.pm')
-rw-r--r--perl-install/lvm.pm133
1 files changed, 115 insertions, 18 deletions
diff --git a/perl-install/lvm.pm b/perl-install/lvm.pm
index 05beddc19..bf212bd6f 100644
--- a/perl-install/lvm.pm
+++ b/perl-install/lvm.pm
@@ -1,4 +1,4 @@
-package lvm; # $Id$
+package lvm;
use diagnostics;
use strict;
@@ -12,13 +12,24 @@ use devices;
use fs::type;
use run_program;
+=head1 SYNOPSYS
+
+Manage LVM (PV, VG, LV)
+
+=head1 Functions
+
+=over 4
+
+=cut
+
#- for partition_table_xxx emulation
sub new {
my ($class, $name) = @_;
- $name =~ s/\W/_/g;
+ $name =~ s/[^\w-]/_/g;
$name = substr($name, 0, 63); # max length must be < NAME_LEN / 2 where NAME_LEN is 128
- bless { disks => [], VG_name => $name }, $class;
+ bless { disks => [], VG_name => $name, device => $name }, $class;
}
+sub use_pt_type { 0 }
sub hasExtended { 0 }
sub adjustStart {}
sub adjustEnd {}
@@ -28,17 +39,38 @@ sub cylinder_size {
$hd->{extent_size};
}
-init() or log::l("lvm::init failed");
+=item detect_durting_install()
+
+Explicitly scan VGs.
+
+=cut
+
+sub detect_during_install() {
+ run_program::run('lvm2', 'vgscan');
+ run_program::run('lvm2', 'vgchange', '-a', 'y');
+}
+
+=item init()
+
+Loads LVM modules and scan VGs (if in installer, not in standalone tool).
+
+=cut
sub init() {
devices::init_device_mapper();
- if ($::isInstall) {
- run_program::run('lvm2', 'vgscan');
- run_program::run('lvm2', 'vgchange', '-a', 'y');
- }
+ detect_during_install() if $::isInstall || $::isLiveInstall;
1;
}
+init() or log::l("lvm::init failed");
+
+=item lvm_cmd(...)
+
+Run a LVM command, then rescan VG.
+See run_program::run() for arguments.
+
+=cut
+
sub lvm_cmd {
if (my $r = run_program::run('lvm2', @_)) {
$r;
@@ -46,19 +78,32 @@ sub lvm_cmd {
$? >> 8 == 98 or return;
#- sometimes, it needs running vgscan again, doing so:
+ log::l("forcing rescan because of prior failure");
run_program::run('lvm2', 'vgscan');
run_program::run('lvm2', @_);
}
}
+
+=item lvm_cmd_or_die($prog, @para)
+
+Like lvm_cmd() but die if there's an error.
+
+=cut
+
sub lvm_cmd_or_die {
my ($prog, @para) = @_;
- lvm_cmd($prog, @para) or die "$prog failed\n";
+ my @err;
+ lvm_cmd("2>", \@err, $prog, @para) or do {
+ my $err = $err[-1]; # prevent "Modification of non-creatable array value attempted"
+ chomp($err);
+ die "$prog failed: $err\n";
+ };
}
sub check {
- my ($in) = @_;
-
- $in->do_pkgs->ensure_binary_is_installed('lvm2', 'lvm2') or return;
+ my ($do_pkgs) = @_;
+ local $::prefix = ''; # We want lvm2 on current system
+ $do_pkgs->ensure_binary_is_installed('lvm2', 'lvm2') or return;
init();
1;
}
@@ -103,6 +148,12 @@ sub lv_nb_pvs {
listlength(lv_to_pvs($lv));
}
+=item get_lvs($lvm)
+
+Return list of LVs.
+
+=cut
+
sub get_lvs {
my ($lvm) = @_;
my @l = run_program::get_stdout('lvm2', 'lvs', '--noheadings', '--nosuffix', '--units', 's', '-o', 'lv_name', $lvm->{VG_name}) =~ /(\S+)/g;
@@ -110,13 +161,20 @@ sub get_lvs {
[
map {
my $device = "$lvm->{VG_name}/$_";
- my $fs_type = -e "/dev/$device" && fs::type::fs_type_from_magic({ device => $device });
-
- { device => $device,
+ my $p = fs::wild_device::to_subpart("/dev/$device");
+ my $part = {
+ device => $device,
lv_name => $_,
rootDevice => $lvm->{VG_name},
- fs_type => $fs_type || 'ext2',
+ minor => $p->{minor},
+ major => $p->{major},
size => get_lv_size($device) };
+ if (my $type = -e "/dev/$device" && fs::type::type_subpart_from_magic($part)) {
+ put_in_hash($part, $type);
+ } else {
+ $part->{fs_type} = defaultFS();
+ }
+ $part;
} @l
];
}
@@ -124,6 +182,7 @@ sub get_lvs {
sub vg_add {
my ($part) = @_;
my $dev = expand_symlinks(devices::make($part->{device}));
+ output($dev, '\0' x 512); #- help pvcreate
lvm_cmd_or_die('pvcreate', '-y', '-ff', $dev);
my $prog = lvm_cmd('vgs', $part->{lvm}) ? 'vgextend' : 'vgcreate';
lvm_cmd_or_die($prog, $part->{lvm}, $dev);
@@ -161,10 +220,21 @@ sub lv_delete {
@$list = grep { $_ != $lv } @$list;
}
+sub suggest_lv_name_from_mnt_point {
+ my ($lv) = @_;
+ my $str = $lv->{mntpoint};
+ $str = "root" if $str eq '/';
+ $str =~ s!^/!!;
+ $str =~ s!/!_!g;
+ $str =~ s! !_!g;
+ 'lv_' . $str;
+}
+
sub suggest_lv_name {
my ($lvm, $lv) = @_;
my $list = $lvm->{primary}{normal} ||= [];
- $lv->{lv_name} ||= 1 + max(map { if_($_->{device} =~ /(\d+)$/, $1) } @$list);
+ $lv->{lv_name} ||= suggest_lv_name_from_mnt_point($lv);
+ $lv->{lv_name} ||= "lv_" . (1 + max(map { if_($_->{device} =~ /(\d+)$/, $1) } @$list));
}
sub lv_create {
@@ -175,7 +245,7 @@ sub lv_create {
if ($lv->{mntpoint} eq '/boot' && lv_nb_pvs($lv) > 1) {
lvm_cmd_or_die('lvremove', '-f', "/dev/$lv->{device}");
- die N("The bootloader can't handle /boot on multiple physicals volumes");
+ die N("The bootloader can't handle /boot on multiple physical volumes");
}
$lv->{size} = get_lv_size($lv->{device}); #- the created size is smaller than asked size
@@ -191,4 +261,31 @@ sub lv_resize {
$lv->{size} = get_lv_size($lv->{device}); #- the resized partition may not be the exact asked size
}
+sub add_to_VG {
+ my ($part, $lvm) = @_;
+
+ $part->{lvm} = $lvm->{VG_name};
+ push @{$lvm->{disks}}, $part;
+ delete $part->{mntpoint};
+
+ vg_add($part);
+ update_size($lvm);
+}
+
+sub create_singleton_vg {
+ my ($lvms, $part) = @_;
+
+ my %existing = map { $_->{VG_name} => 1 } @$lvms;
+ my $VG_name = find { !$existing{$_} } map { "VG$_" } 1 .. 100 or internal_error();
+
+ my $lvm = new lvm($VG_name);
+ push @$lvms, $lvm;
+
+ add_to_VG($part, $lvm);
+}
+
+=back
+
+=cut
+
1;