[pve-devel] [RFC PATCH container] snapshot: replace global sync with a namespace sync
Wolfgang Bumiller
w.bumiller at proxmox.com
Thu Feb 11 09:26:36 CET 2016
snapshot_create() called did a global 'sync' after freeze()
which syncs everything including all other containers and
the host. So if you want to snapshot container A while
container B tries to write to a broken NFS mount the
snapshot will hang in that sync call.
Instead we now enter the container's mount namespace and do
a syncfs() on all of its mountpoints.
---
This patch needs the syncfs() patch for pve-common.
src/PVE/LXC.pm | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 73 insertions(+), 2 deletions(-)
diff --git a/src/PVE/LXC.pm b/src/PVE/LXC.pm
index 0a6b451..6545df5 100644
--- a/src/PVE/LXC.pm
+++ b/src/PVE/LXC.pm
@@ -4,10 +4,12 @@ use strict;
use warnings;
use POSIX qw(EINTR);
+use Socket;
+
use File::Path;
use File::Spec;
use Cwd qw();
-use Fcntl ':flock';
+use Fcntl qw(O_RDONLY :flock);
use PVE::Cluster qw(cfs_register_file cfs_read_file);
use PVE::Storage;
@@ -1797,6 +1799,75 @@ sub has_feature {
return $err ? 0 : 1;
}
+my $enter_namespace = sub {
+ my ($vmid, $pid, $which, $type) = @_;
+ sysopen my $fd, "/proc/$pid/ns/$which", O_RDONLY
+ or die "failed to open $which namespace of container $vmid: $!\n";
+ PVE::Tools::setns(fileno($fd), $type)
+ or die "failed to enter $which namespace of container $vmid: $!\n";
+ close $fd;
+};
+
+my $do_syncfs = sub {
+ my ($vmid, $pid, $socket) = @_;
+
+ &$enter_namespace($vmid, $pid, 'mnt', PVE::Tools::CLONE_NEWNS);
+
+ # Tell the parent process to start reading our /proc/mounts
+ print {$socket} "go\n";
+ $socket->flush();
+
+ # Receive /proc/self/mounts
+ my $mountdata = do { local $/ = undef; <$socket> };
+ close $socket;
+
+ # Now sync all mountpoints...
+ my $mounts = PVE::ProcFSTools::parse_mounts($mountdata);
+ foreach my $mp (@$mounts) {
+ my ($what, $dir, $fs) = @$mp;
+ next if $fs eq 'fuse.lxcfs';
+ eval { PVE::Tools::sync_mountpoint($dir); };
+ warn $@ if $@;
+ }
+};
+
+sub sync_container_namespace {
+ my ($vmid) = @_;
+ my $pid = find_lxc_pid($vmid);
+
+ # SOCK_DGRAM is nicer for barriers but cannot be slurped
+ socketpair my $pfd, my $cfd, AF_UNIX, SOCK_STREAM, PF_UNSPEC
+ or die "failed to create socketpair: $!\n";
+
+ my $child = fork();
+ die "fork failed: $!\n" if !defined($child);
+
+ if (!$child) {
+ eval {
+ close $pfd;
+ &$do_syncfs($vmid, $pid, $cfd);
+ };
+ if (my $err = $@) {
+ warn $err;
+ POSIX::_exit(1);
+ }
+ POSIX::_exit(0);
+ }
+ close $cfd;
+ my $go = <$pfd>;
+ die "failed to enter container namespace\n" if $go ne "go\n";
+
+ open my $mounts, '<', "/proc/$child/mounts"
+ or die "failed to open container's /proc/mounts: $!\n";
+ my $mountdata = do { local $/ = undef; <$mounts> };
+ close $mounts;
+ print {$pfd} $mountdata;
+ close $pfd;
+
+ while (waitpid($child, 0) != $child) {}
+ die "failed to sync container namespace\n" if $? != 0;
+}
+
sub snapshot_create {
my ($vmid, $snapname, $comment) = @_;
@@ -1814,7 +1885,7 @@ sub snapshot_create {
if ($running) {
$unfreeze = 1;
PVE::Tools::run_command(['/usr/bin/lxc-freeze', '-n', $vmid]);
- PVE::Tools::run_command(['/bin/sync']);
+ sync_container_namespace($vmid);
};
my $storecfg = PVE::Storage::config();
--
2.1.4
More information about the pve-devel
mailing list