]> git.proxmox.com Git - pve-storage.git/blobdiff - PVE/Storage/LvmThinPlugin.pm
file/volume size info: add actual errors to untaint messages
[pve-storage.git] / PVE / Storage / LvmThinPlugin.pm
index c8b48f0f8067bc9d52d8eda8050c50327d300536..4ba6f901d89f047157b59ac0c799d1b6e37d7773 100644 (file)
@@ -2,8 +2,9 @@ package PVE::Storage::LvmThinPlugin;
 
 use strict;
 use warnings;
-use Data::Dumper;
+
 use IO::File;
+
 use PVE::Tools qw(run_command trim);
 use PVE::Storage::Plugin;
 use PVE::Storage::LVMPlugin;
@@ -15,6 +16,12 @@ use PVE::JSONSchema qw(get_standard_option);
 # lvcreate -n pvepool -L 20G pve
 # lvconvert --type thin-pool pve/pvepool
 
+# NOTE: volumes which were created as linked clones of another base volume
+# are currently not tracking this relationship in their volume IDs. this is
+# generally not a problem, as LVM thin allows deletion of such base volumes
+# without affecting the linked clones. this leads to increased disk usage
+# when migrating LVM-thin volumes, which is normally prevented for linked clones.
+
 use base qw(PVE::Storage::LVMPlugin);
 
 sub type {
@@ -43,9 +50,13 @@ sub options {
         nodes => { optional => 1 },
        disable => { optional => 1 },
        content => { optional => 1 },
+       bwlimit => { optional => 1 },
     };
 }
 
+# NOTE: the fourth and fifth element of the returned array are always
+# undef, even if the volume is a linked clone of another volume. see note
+# at beginning of file.
 sub parse_volname {
     my ($class, $volname) = @_;
 
@@ -75,7 +86,7 @@ sub alloc_image {
 
     die "unsupported format '$fmt'" if $fmt ne 'raw';
 
-    die "illegal name '$name' - sould be 'vm-$vmid-*'\n"
+    die "illegal name '$name' - should be 'vm-$vmid-*'\n"
        if  $name && $name !~ m/^vm-$vmid-/;
 
     my $vgs = PVE::Storage::LVMPlugin::lvm_vgs();
@@ -84,9 +95,7 @@ sub alloc_image {
 
     die "no such volume group '$vg'\n" if !defined ($vgs->{$vg});
 
-    my $lvs = PVE::Storage::LVMPlugin::lvm_list_volumes($vg);
-
-    $name = PVE::Storage::LVMPlugin::lvm_find_free_diskname($lvs, $vg, $storeid, $vmid)
+    $name = $class->find_free_diskname($storeid, $scfg, $vmid)
        if !$name;
 
     my $cmd = ['/sbin/lvcreate', '-aly', '-V', "${size}k", '--name', $name,
@@ -108,7 +117,7 @@ sub free_image {
 
        # remove all volume snapshots first
        foreach my $lv (keys %$dat) {
-           next if $lv !~ m/^snap_${volname}_(\w+)$/;
+           next if $lv !~ m/^snap_${volname}_${PVE::JSONSchema::CONFIGID_RE}$/;
            my $cmd = ['/sbin/lvremove', '-f', "$vg/$lv"];
            run_command($cmd, errmsg => "lvremove snapshot '$vg/$lv' error");
        }
@@ -156,6 +165,7 @@ sub list_images {
 
            push @$res, {
                volid => $volid, format => 'raw', size => $info->{lv_size}, vmid => $owner,
+               ctime => $info->{ctime},
            };
        }
     }
@@ -169,9 +179,13 @@ sub list_thinpools {
     my $lvs = PVE::Storage::LVMPlugin::lvm_list_volumes($vg);
     my $thinpools = [];
 
-    foreach my $lvname (keys %{$lvs->{$vg}}) {
-       next if $lvs->{$vg}->{$lvname}->{lv_type} ne 't';
-       push @$thinpools, { lv => $lvname };
+    foreach my $vg (keys %$lvs) {
+       foreach my $lvname (keys %{$lvs->{$vg}}) {
+           next if $lvs->{$vg}->{$lvname}->{lv_type} ne 't';
+           my $lv = $lvs->{$vg}->{$lvname};
+           $lv->{lv} = $lvname;
+           push @$thinpools, $lv;
+       }
     }
 
     return $thinpools;
@@ -209,6 +223,9 @@ sub activate_volume {
        my $snapvol = "snap_${volname}_$snapname";
        my $cmd = ['/sbin/lvchange', '-ay', '-K', "$vg/$snapvol"];
        run_command($cmd, errmsg => "activate_volume '$vg/$snapvol' error");
+    } elsif ($volname =~ /^base-/) {
+       my $cmd = ['/sbin/lvchange', '-ay', '-K', "$vg/$volname"];
+       run_command($cmd, errmsg => "activate_volume '$vg/$volname' error");
     } else {
        # other volumes are active by default
     }
@@ -224,6 +241,9 @@ sub deactivate_volume {
        my $snapvol = "snap_${volname}_$snapname";
        my $cmd = ['/sbin/lvchange', '-an', "$vg/$snapvol"];
        run_command($cmd, errmsg => "deactivate_volume '$vg/$snapvol' error");
+    } elsif ($volname =~ /^base-/) {
+       my $cmd = ['/sbin/lvchange', '-an', "$vg/$volname"];
+       run_command($cmd, errmsg => "deactivate_volume '$vg/$volname' error");
     } else {
        # other volumes are kept active
     }
@@ -247,9 +267,7 @@ sub clone_image {
        $lv = "$vg/$volname";
     }
 
-    my $lvs = PVE::Storage::LVMPlugin::lvm_list_volumes($vg);
-
-    my $name =  PVE::Storage::LVMPlugin::lvm_find_free_diskname($lvs, $vg, $storeid, $vmid);
+    my $name = $class->find_free_diskname($storeid, $scfg, $vmid);
 
     my $cmd = ['/sbin/lvcreate', '-n', $name, '-prw', '-kn', '-s', $lv];
     run_command($cmd, errmsg => "clone image '$lv' error");
@@ -353,4 +371,11 @@ sub volume_has_feature {
     return undef;
 }
 
+# used in LVMPlugin->volume_import
+sub volume_import_write {
+    my ($class, $input_fh, $output_file) = @_;
+    run_command(['dd', "of=$output_file", 'conv=sparse', 'bs=64k'],
+       input => '<&'.fileno($input_fh));
+}
+
 1;