]> git.proxmox.com Git - pve-container.git/commitdiff
Add mp support to snapshots
authorFabian Grünbichler <f.gruenbichler@proxmox.com>
Wed, 24 Feb 2016 11:28:34 +0000 (12:28 +0100)
committerDietmar Maurer <dietmar@proxmox.com>
Thu, 25 Feb 2016 08:19:50 +0000 (09:19 +0100)
Modelled after QemuServer's way of handling multiple drives.

src/PVE/LXC.pm
src/PVE/VZDump/LXC.pm

index 6046c46bd79bfb0e722f1dce9127cb68c6dac005..dcec7754701a2146c7041f319e1d19d5a82e8551 100644 (file)
@@ -1892,10 +1892,6 @@ sub has_feature {
        return if $vzdump && $ms ne 'rootfs' && !$mountpoint->{backup};
        
        $err = 1 if !PVE::Storage::volume_has_feature($storecfg, $feature, $mountpoint->{volume}, $snapname);
-
-       # TODO: implement support for mountpoints
-       die "unable to handle mountpoint '$ms' - feature not implemented\n"
-           if $ms ne 'rootfs';
     });
 
     return $err ? 0 : 1;
@@ -1970,43 +1966,54 @@ sub sync_container_namespace {
     die "failed to sync container namespace\n" if $? != 0;
 }
 
+sub check_freeze_needed {
+    my ($vmid, $config, $save_vmstate) = @_;
+
+    my $ret = check_running($vmid);
+    return ($ret, $ret);
+}
+
 sub snapshot_create {
     my ($vmid, $snapname, $save_vmstate, $comment) = @_;
 
     my $snap = snapshot_prepare($vmid, $snapname, $save_vmstate, $comment);
 
+    $save_vmstate = 0 if !$snap->{vmstate};
+
     my $conf = load_config($vmid);
 
-    my $running = check_running($vmid);
-    
-    my $unfreeze = 0;
+    my ($running, $freezefs) = check_freeze_needed($vmid, $conf, $snap->{vmstate});
 
     my $drivehash = {};
 
     eval {
-       if ($running) {
-           $unfreeze = 1;
+       if ($freezefs) {
            PVE::Tools::run_command(['/usr/bin/lxc-freeze', '-n', $vmid]);
            sync_container_namespace($vmid);
-       };
+       }
 
        my $storecfg = PVE::Storage::config();
-       my $rootinfo = parse_ct_rootfs($conf->{rootfs});
-       my $volid = $rootinfo->{volume};
+       foreach_mountpoint($conf, sub {
+           my ($ms, $mountpoint) = @_;
 
-       PVE::Storage::volume_snapshot($storecfg, $volid, $snapname);
-       $drivehash->{rootfs} = 1;
+           return if $snapname eq 'vzdump' && $ms ne 'rootfs' && !$mountpoint->{backup};
+           PVE::Storage::volume_snapshot($storecfg, $mountpoint->{volume}, $snapname);
+           $drivehash->{$ms} = 1;
+       });
     };
     my $err = $@;
     
-    if ($unfreeze) {
-       eval { PVE::Tools::run_command(['/usr/bin/lxc-unfreeze', '-n', $vmid]); };
-       warn $@ if $@;
+    if ($running) {
+       if ($freezefs) {
+           eval { PVE::Tools::run_command(['/usr/bin/lxc-unfreeze', '-n', $vmid]); };
+           warn $@ if $@;
+       }
     }
     
     if ($err) {
+       warn "snapshot create failed: starting cleanup\n";
        eval { snapshot_delete($vmid, $snapname, 1, $drivehash); };
-       warn "$@\n" if $@;
+       warn "$@" if $@;
        die "$err\n";
     }
 
@@ -2020,6 +2027,7 @@ sub snapshot_delete {
     my $prepare = 1;
 
     my $snap;
+    my $unused = [];
 
     my $unlink_parent = sub {
        my ($confref, $new_parent) = @_;
@@ -2061,7 +2069,11 @@ sub snapshot_delete {
            if ($remove_drive eq 'vmstate') {
                die "implement me - saving vmstate\n";
            } else {
-               die "implement me - remove drive\n";
+               my $value = $snap->{$remove_drive};
+               my $mountpoint = $remove_drive eq 'rootfs' ? parse_ct_rootfs($value, 1) : parse_ct_mountpoint($value, 1);
+               delete $snap->{$remove_drive};
+               add_unused_volume($snap, $mountpoint->{volume})
+                   if (!is_volume_in_use($snap, $mountpoint->{volume}));
            }
        }
 
@@ -2070,6 +2082,10 @@ sub snapshot_delete {
        } else {
            delete $conf->{snapshots}->{$snapname};
            delete $conf->{lock} if $drivehash;
+           foreach my $volid (@$unused) {
+               add_unused_volume($conf, $volid)
+                   if (!is_volume_in_use($conf, $volid));
+           }
        }
 
        write_config($vmid, $conf);
@@ -2086,17 +2102,22 @@ sub snapshot_delete {
     };
 
     # now remove all volume snapshots
-    # only rootfs for now!
-    eval {
-       my $rootfs = $snap->{rootfs};
-       my $rootinfo = parse_ct_rootfs($rootfs);
-       my $volid = $rootinfo->{volume};
-       PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snapname);
-    };
-    if (my $err = $@) {
-       die $err if !$force;
-       warn $err;
-    }
+    foreach_mountpoint($snap, sub {
+       my ($ms, $mountpoint) = @_;
+
+       return if $snapname eq 'vzdump' && $ms ne 'rootfs' && !$mountpoint->{backup};
+       if (!$drivehash || $drivehash->{$ms}) {
+           eval { PVE::Storage::volume_snapshot_delete($storecfg, $mountpoint->{volume}, $snapname); };
+           if (my $err = $@) {
+               die $err if !$force;
+               warn $err;
+           }
+       }
+
+       # save changes (remove mp from snapshot)
+       lock_config($vmid, $updatefn, $ms) if !$force;
+       push @$unused, $mountpoint->{volume};
+    });
 
     # now cleanup config
     $prepare = 0;
@@ -2125,12 +2146,11 @@ sub snapshot_rollback {
 
     my $snap = &$get_snapshot_config();
 
-    # only for rootfs for now!
-    my $rootfs = $snap->{rootfs};
-    my $rootinfo = parse_ct_rootfs($rootfs);
-    my $volid = $rootinfo->{volume};
+    foreach_mountpoint($snap, sub {
+       my ($ms, $mountpoint) = @_;
 
-    PVE::Storage::volume_rollback_is_possible($storecfg, $volid, $snapname);
+       PVE::Storage::volume_rollback_is_possible($storecfg, $mountpoint->{volume}, $snapname);
+    });
 
     my $updatefn = sub {
 
@@ -2174,8 +2194,11 @@ sub snapshot_rollback {
 
     lock_config($vmid, $updatefn);
 
-    # only rootfs for now!
-    PVE::Storage::volume_snapshot_rollback($storecfg, $volid, $snapname);
+    foreach_mountpoint($snap, sub {
+       my ($ms, $mountpoint) = @_;
+
+       PVE::Storage::volume_snapshot_rollback($storecfg, $mountpoint->{volume}, $snapname);
+    });
 
     $prepare = 0;
     lock_config($vmid, $updatefn);
index 1d24036e92aed7a32de35ea9562cad93ae48b07a..7269ce8cf8b47dfbc78d4b387d397ff5ae0b20fa 100644 (file)
@@ -104,13 +104,14 @@ sub prepare {
 
     my $disks = $task->{disks} = [];
     my $exclude_dirs = $task->{exclude_dirs} = [];
+    my $volids = $task->{volids} = [];
 
     $task->{hostname} = $conf->{'hostname'} || "CT$vmid";
 
     my ($id_map, $rootuid, $rootgid) = PVE::LXC::parse_id_maps($conf);
     $task->{userns_cmd} = PVE::LXC::userns_command($id_map);
 
-    my $volid_list = [];
+    my $volids = $task->{volids} = [];
     PVE::LXC::foreach_mountpoint($conf, sub {
        my ($name, $data) = @_;
        my $volid = $data->{volume};
@@ -125,7 +126,7 @@ sub prepare {
        }
 
        push @$disks, $data;
-       push @$volid_list, $volid
+       push @$volids, $volid
            if $type eq 'volume';
     });
 
@@ -146,12 +147,12 @@ sub prepare {
        &$check_mountpoint_empty($rootdir);
 
        # set snapshot_count (freezes CT if snapshot_count > 1)
-       $task->{snapshot_count} = scalar(@$volid_list);
+       $task->{snapshot_count} = scalar(@$volids);
     } elsif ($mode eq 'stop') {
        my $rootdir = $default_mount_point;
        mkpath $rootdir;
        &$check_mountpoint_empty($rootdir);
-       PVE::Storage::activate_volumes($storage_cfg, $volid_list);
+       PVE::Storage::activate_volumes($storage_cfg, $volids);
     } elsif ($mode eq 'suspend') {
        my $pid = PVE::LXC::find_lxc_pid($vmid);
        foreach my $disk (@$disks) {
@@ -220,13 +221,12 @@ sub snapshot {
        if !($conf->{snapshots} && $conf->{snapshots}->{vzdump});
 
     my $disks = $task->{disks};
-    #todo: reevaluate bind/dev mount handling when implementing snapshots for mps
-    my $volid_list = [map { $_->{volume} } @$disks];
+    my $volids = $task->{volids};
 
     my $rootdir = $default_mount_point;
     my $storage_cfg = $self->{storecfg};
 
-    PVE::Storage::activate_volumes($storage_cfg, $volid_list, 'vzdump');
+    PVE::Storage::activate_volumes($storage_cfg, $volids, 'vzdump');
     foreach my $disk (@$disks) {
        $disk->{dir} = "${rootdir}$disk->{mp}";
        PVE::LXC::mountpoint_mount($disk, $rootdir, $storage_cfg, 'vzdump');
@@ -320,6 +320,12 @@ sub archive {
            push @sources, ".$disk->{mp}";
        }
        $task->{snapdir} = $rootdir;
+    } elsif ($task->{mode} eq 'snapshot') {
+       # mounting the vzdump snapshots and setting $snapdir is already done,
+       # but we need to include all mountpoints here!
+       foreach my $disk (@$disks) {
+           push @sources, ".$disk->{mp}";
+       }
     } else {
        # the data was rsynced to a temporary location, only use '.' to avoid
        # having mountpoints duplicated