[pve-devel] [PATCHV3 pve-container 1/4] Add the functionality of full clone

Wolfgang Link w.link at proxmox.com
Tue May 10 11:13:31 CEST 2016


---
 src/PVE/API2/LXC.pm | 21 +++++++++----------
 src/PVE/LXC.pm      | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 68 insertions(+), 11 deletions(-)

diff --git a/src/PVE/API2/LXC.pm b/src/PVE/API2/LXC.pm
index 95932a9..0bcadc3 100644
--- a/src/PVE/API2/LXC.pm
+++ b/src/PVE/API2/LXC.pm
@@ -1079,6 +1079,7 @@ __PACKAGE__->register_method({
 
 	my $storage = extract_param($param, 'storage');
 
+	die "Full clone requires a storage.\n"if $param->{full} && !$storage;
         my $localnode = PVE::INotify::nodename();
 
 	my $storecfg = PVE::Storage::config();
@@ -1132,10 +1133,6 @@ __PACKAGE__->register_method({
 		    if ($mp->{type} eq 'volume') {
 			my $volid = $mp->{volume};
 			if ($param->{full}) {
-			    die "fixme: full clone not implemented";
-
-			    die "Full clone feature for '$volid' is not available\n"
-				if !PVE::Storage::volume_has_feature($storecfg, 'copy', $volid, $snapname, $running);
 			    $fullclone->{$opt} = 1;
 			} else {
 			    # not full means clone instead of copy
@@ -1182,18 +1179,20 @@ __PACKAGE__->register_method({
 		    foreach my $opt (keys %$mountpoints) {
 			my $mp = $mountpoints->{$opt};
 			my $volid = $mp->{volume};
+			my $newvolid;
 
 			if ($fullclone->{$opt}) {
-			    die "fixme: full clone not implemented\n";
+			    print "create full clone of mountpoint $opt ($volid)\n";
+			    $newvolid = PVE::LXC::copy_volume($mp, $vmid, $newid, $storage, $storecfg, $conf);
 			} else {
 			    print "create linked clone of mountpoint $opt ($volid)\n";
-			    my $newvolid = PVE::Storage::vdisk_clone($storecfg, $volid, $newid, $snapname);
-			    push @$newvollist, $newvolid;
-			    $mp->{volume} = $newvolid;
-
-			    $newconf->{$opt} = PVE::LXC::Config->print_ct_mountpoint($mp, $opt eq 'rootfs');
-			    PVE::LXC::Config->write_config($newid, $newconf);
+			    $newvolid = PVE::Storage::vdisk_clone($storecfg, $volid, $newid, $snapname);
 			}
+			push @$newvollist, $newvolid;
+			$mp->{volume} = $newvolid;
+
+			$newconf->{$opt} = PVE::LXC::Config->print_ct_mountpoint($mp, $opt eq 'rootfs');
+			PVE::LXC::Config->write_config($newid, $newconf);
 		    }
 
 		    delete $newconf->{lock};
diff --git a/src/PVE/LXC.pm b/src/PVE/LXC.pm
index ea68b71..047b5d1 100644
--- a/src/PVE/LXC.pm
+++ b/src/PVE/LXC.pm
@@ -22,6 +22,7 @@ use PVE::AccessControl;
 use PVE::ProcFSTools;
 use PVE::LXC::Config;
 use Time::HiRes qw (gettimeofday);
+use Storable;
 
 use Data::Dumper;
 
@@ -1355,5 +1356,62 @@ sub userns_command {
     return [];
 }
 
+sub copy_volume {
+    my ($mp, $vmid, $newid, $storage, $storage_cfg, $conf) = @_;
+    my $mount_dir = "/tmp/$vmid";
+    my $dest = "$mount_dir\/dest";
+    my $src =  "$mount_dir\/src";
+
+    my $new_format =  $storage_cfg->{ids}->{$storage}->{type} eq "zfspool" ? 'subvol' : 'raw';
+
+    my $new_volid = PVE::Storage::vdisk_alloc($storage_cfg, $storage, $newid, $new_format, undef, $mp->{size}/1024);
+
+    #simplify mount struct. See mountpoint_mount().
+    my $tmp_mp = $mp->{mp};
+    $mp->{mp} = '/';
+
+    my $new_mp = Storable::dclone($mp);
+    $new_mp->{volume} = $new_volid;
+
+    #get id's for unprivileged container
+    my (undef, $rootuid, $rootgid) = parse_id_maps($conf);
+
+    my $path = PVE::Storage::path($storage_cfg, $new_volid, undef);
+
+    eval {
+	mkfs($path, $rootuid, $rootgid) if $new_format ne "subvol";
+
+	mkdir $mount_dir;
+	mkdir $dest;
+	mkdir $src;
+
+	#mount for copy mp 
+	mountpoint_mount($mp, $src, $storage_cfg);
+	mountpoint_mount($new_mp, $dest, $storage_cfg);
+
+	PVE::Tools::run_command(['/usr/bin/rsync', '--stats', '-X', '-A', '--numeric-ids',
+				 '--whole-file', '--inplace', '--one-file-system', '-aH',
+				 "$src\/.", $dest]);
+
+    };
+    my $err = $@;
+    eval { PVE::Tools::run_command(['/bin/umount', '--lazy', $src], errfunc => sub{})};
+    warn "Can't umount $src\n" if $@;
+    eval { PVE::Tools::run_command(['/bin/umount', '--lazy', $dest], errfunc => sub{})};
+    warn "Can't umount $src\n" if $@;
+
+    rmdir $dest;
+    rmdir $src;
+    rmdir $mount_dir;
+
+    #set it back to orgin value
+    $mp->{mp} = $tmp_mp;
+
+    if ($err) {
+	PVE::Storage::vdisk_free($storage_cfg, $new_volid);
+	die $err;
+    }
+    return $new_volid;
+}
 
 1;
-- 
2.1.4





More information about the pve-devel mailing list