[pve-devel] [PATCH 7/8] add socat and unix socket for storage migration

Alexandre Derumier aderumier at odiso.com
Tue Jan 3 15:03:18 CET 2017


This is a workaround for nbd infinite timeout connect

Signed-off-by: Alexandre Derumier <aderumier at odiso.com>
---
 PVE/QemuServer.pm | 52 ++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 48 insertions(+), 4 deletions(-)

diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index a2acf0c..9585832 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -5913,13 +5913,36 @@ sub qemu_drive_mirror {
 
     my $qemu_target;
     my $format;
+    $jobs->{"drive-$drive"} = {};
 
-    if($dst_volid =~ /^nbd:(localhost|[\d\.]+|\[[\d\.:a-fA-F]+\]):(\d+)/) {
-	$qemu_target = $dst_volid;
+    if($dst_volid =~ /^nbd:(localhost|[\d\.]+|\[[\d\.:a-fA-F]+\]):(\d+):exportname=(\S+)/) {
 	my $server = $1;
 	my $port = $2;
+	my $exportname = $3;
+
 	$format = "nbd";
-	die "can't connect remote nbd server $server:$port" if !PVE::Network::tcp_ping($server, $port, 2);
+	my $unixsocket = "/run/qemu-server/$vmid.mirror-drive-$drive";
+	$qemu_target = "nbd+unix:///$exportname?socket=$unixsocket";
+	my $cmd = ['socat', "UNIX-LISTEN:$unixsocket,fork", "TCP:$server:$2,connect-timeout=1"];
+
+	my $pid = fork();
+	if (!defined($pid)) {
+	    die "forking socat tunnel failed";
+	} elsif ($pid == 0) {
+	    exec(@$cmd);
+	    exit(-1);
+	} else {
+
+	    $jobs->{"drive-$drive"}->{pid} = $pid;
+
+	    my $timeout = 0;
+	    while (1) {
+		last if -S $unixsocket; 
+		die if $timeout > 5;
+		$timeout++;
+		sleep 1;
+	    }
+	}
     } else {
 
 	my $storecfg = PVE::Storage::config();
@@ -5940,12 +5963,12 @@ sub qemu_drive_mirror {
     print "drive mirror is starting for drive-$drive\n";
 
     eval { vm_mon_cmd($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
+
     if (my $err = $@) {
 	eval { PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs) };
 	die "mirroring error: $err";
     }
 
-    $jobs->{"drive-$drive"} = {};
 
     qemu_drive_mirror_monitor ($vmid, $vmiddst, $jobs, $skipcomplete);
 }
@@ -6016,6 +6039,7 @@ sub qemu_drive_mirror_monitor {
 			}else {
 			    print "$job : complete ok : flushing pending writes\n";
 			    $jobs->{$job}->{complete} = 1;
+			    eval { qemu_blockjobs_finish_tunnel($vmid, $job, $jobs->{$job}->{pid}) } ;
 			}
 		    }
 		}
@@ -6053,6 +6077,7 @@ sub qemu_blockjobs_cancel {
 
 	    if(defined($jobs->{$job}->{cancel}) && !defined($running_jobs->{$job})) {
 		print "$job : finished\n";
+		eval { qemu_blockjobs_finish_tunnel($vmid, $job, $jobs->{$job}->{pid}) } ;
 		delete $jobs->{$job};
 	    }
 	}
@@ -6063,6 +6088,25 @@ sub qemu_blockjobs_cancel {
     }
 }
 
+sub qemu_blockjobs_finish_tunnel {
+   my ($vmid, $job, $cpid) = @_;
+
+   return if !$cpid;
+
+   for (my $i = 1; $i < 20; $i++) {
+	my $waitpid = waitpid($cpid, WNOHANG);
+	last if (defined($waitpid) && ($waitpid == $cpid));
+ 
+	if ($i == 10) {
+	    kill(15, $cpid);
+	} elsif ($i >= 15) {
+	    kill(9, $cpid);
+	}
+	sleep (1);
+    }
+    unlink "/run/qemu-server/$vmid.mirror-$job";
+}
+
 sub clone_disk {
     my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
 	$newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete) = @_;
-- 
2.1.4



More information about the pve-devel mailing list