[pve-devel] [PATCH container 1/1] deal with disabled cgroup subsystems

Wolfgang Bumiller w.bumiller at proxmox.com
Thu Jun 21 10:07:41 CEST 2018


When a user disables a cgroup subsystem via eg. a kernel
command line we shouldn't try to generate lxc.cgroup.*
entries for it.

Signed-off-by: Wolfgang Bumiller <w.bumiller at proxmox.com>
---
 src/PVE/CLI/pct.pm |   6 ++
 src/PVE/LXC.pm     | 166 ++++++++++++++++++++++++++++++++---------------------
 2 files changed, 107 insertions(+), 65 deletions(-)

diff --git a/src/PVE/CLI/pct.pm b/src/PVE/CLI/pct.pm
index 897d595..9eb4ac0 100755
--- a/src/PVE/CLI/pct.pm
+++ b/src/PVE/CLI/pct.pm
@@ -669,6 +669,12 @@ __PACKAGE__->register_method ({
     code => sub {
 	my ($param) = @_;
 
+	my $cgv1 = PVE::LXC::get_cgroup_subsystems();
+	if (!$cgv1->{cpuset}) {
+	    print "cpuset cgroup not available\n";
+	    return undef;
+	}
+
 	my $ctlist = PVE::LXC::config_list();
 
 	my $len = 0;
diff --git a/src/PVE/LXC.pm b/src/PVE/LXC.pm
index 4be1579..bc03792 100644
--- a/src/PVE/LXC.pm
+++ b/src/PVE/LXC.pm
@@ -195,48 +195,62 @@ sub vmstatus {
 
 	my $unpriv = $unprivileged->{$vmid};
 
-	my $memory_stat = read_cgroup_list('memory', $vmid, $unpriv, 'memory.stat');
-	my $mem_usage_in_bytes = read_cgroup_value('memory', $vmid, $unpriv, 'memory.usage_in_bytes');
-
-	$d->{mem} = $mem_usage_in_bytes - $memory_stat->{total_cache};
-	$d->{swap} = read_cgroup_value('memory', $vmid, $unpriv, 'memory.memsw.usage_in_bytes') - $mem_usage_in_bytes;
-
-	my $blkio_bytes = read_cgroup_value('blkio', $vmid, $unpriv, 'blkio.throttle.io_service_bytes', 1);
-	my @bytes = split(/\n/, $blkio_bytes);
-	foreach my $byte (@bytes) {
-	    if (my ($key, $value) = $byte =~ /(Read|Write)\s+(\d+)/) {
-		$d->{diskread} += $2 if $key eq 'Read';
-		$d->{diskwrite} += $2 if $key eq 'Write';
+	if (-d '/sys/fs/cgroup/memory') {
+	    my $memory_stat = read_cgroup_list('memory', $vmid, $unpriv, 'memory.stat');
+	    my $mem_usage_in_bytes = read_cgroup_value('memory', $vmid, $unpriv, 'memory.usage_in_bytes');
+
+	    $d->{mem} = $mem_usage_in_bytes - $memory_stat->{total_cache};
+	    $d->{swap} = read_cgroup_value('memory', $vmid, $unpriv, 'memory.memsw.usage_in_bytes') - $mem_usage_in_bytes;
+	} else {
+	    $d->{mem} = 0;
+	    $d->{swap} = 0;
+	}
+
+	if (-d '/sys/fs/cgroup/blkio') {
+	    my $blkio_bytes = read_cgroup_value('blkio', $vmid, $unpriv, 'blkio.throttle.io_service_bytes', 1);
+	    my @bytes = split(/\n/, $blkio_bytes);
+	    foreach my $byte (@bytes) {
+		if (my ($key, $value) = $byte =~ /(Read|Write)\s+(\d+)/) {
+		    $d->{diskread} += $2 if $key eq 'Read';
+		    $d->{diskwrite} += $2 if $key eq 'Write';
+		}
 	    }
+	} else {
+	    $d->{diskread} = 0;
+	    $d->{diskwrite} = 0;
 	}
 
-	my $pstat = $parse_cpuacct_stat->($vmid, $unpriv);
+	if (-d '/sys/fs/cgroup/cpuacct') {
+	    my $pstat = $parse_cpuacct_stat->($vmid, $unpriv);
 
-	my $used = $pstat->{utime} + $pstat->{stime};
+	    my $used = $pstat->{utime} + $pstat->{stime};
 
-	my $old = $last_proc_vmid_stat->{$vmid};
-	if (!$old) {
-	    $last_proc_vmid_stat->{$vmid} = {
-		time => $cdtime,
-		used => $used,
-		cpu => 0,
-	    };
-	    next;
-	}
+	    my $old = $last_proc_vmid_stat->{$vmid};
+	    if (!$old) {
+		$last_proc_vmid_stat->{$vmid} = {
+		    time => $cdtime,
+		    used => $used,
+		    cpu => 0,
+		};
+		next;
+	    }
 
-	my $dtime = ($cdtime -  $old->{time}) * $cpucount * $cpuinfo->{user_hz};
+	    my $dtime = ($cdtime -  $old->{time}) * $cpucount * $cpuinfo->{user_hz};
 
-	if ($dtime > 1000) {
-	    my $dutime = $used -  $old->{used};
+	    if ($dtime > 1000) {
+		my $dutime = $used -  $old->{used};
 
-	    $d->{cpu} = (($dutime/$dtime)* $cpucount) / $d->{cpus};
-	    $last_proc_vmid_stat->{$vmid} = {
-		time => $cdtime,
-		used => $used,
-		cpu => $d->{cpu},
-	    };
+		$d->{cpu} = (($dutime/$dtime)* $cpucount) / $d->{cpus};
+		$last_proc_vmid_stat->{$vmid} = {
+		    time => $cdtime,
+		    used => $used,
+		    cpu => $d->{cpu},
+		};
+	    } else {
+		$d->{cpu} = $old->{cpu};
+	    }
 	} else {
-	    $d->{cpu} = $old->{cpu};
+	    $d->{cpu} = 0;
 	}
     }
 
@@ -339,6 +353,20 @@ sub parse_ipv4_cidr {
     die "unable to parse ipv4 address/mask\n";
 }
 
+sub get_cgroup_subsystems {
+	my $v1 = {};
+	my $v2 = 0;
+	my $data = PVE::Tools::file_get_contents('/proc/self/cgroup');
+	while ($data =~ /^\d+:([^:\n]*):.*$/gm) {
+		my $type = $1;
+		if (length($type)) {
+			$v1->{$_} = 1 foreach split(/,/, $type);
+		} else {
+			$v2 = 1;
+		}
+	}
+	return wantarray ? ($v1, $v2) : $v1;
+}
 
 sub update_lxc_config {
     my ($vmid, $conf) = @_;
@@ -380,6 +408,8 @@ sub update_lxc_config {
     # files while the container is running!
     $raw .= "lxc.monitor.unshare = 1\n";
 
+    my $cgv1 = get_cgroup_subsystems();
+
     # Should we read them from /etc/subuid?
     if ($unprivileged && !$custom_idmap) {
 	$raw .= "lxc.idmap = u 0 100000 65536\n";
@@ -388,7 +418,7 @@ sub update_lxc_config {
 
     if (!PVE::LXC::Config->has_dev_console($conf)) {
 	$raw .= "lxc.console.path = none\n";
-	$raw .= "lxc.cgroup.devices.deny = c 5:1 rwm\n";
+	$raw .= "lxc.cgroup.devices.deny = c 5:1 rwm\n" if $cgv1->{devices};
     }
 
     my $ttycount = PVE::LXC::Config->get_tty_count($conf);
@@ -400,23 +430,27 @@ sub update_lxc_config {
     my $utsname = $conf->{hostname} || "CT$vmid";
     $raw .= "lxc.uts.name = $utsname\n";
 
-    my $memory = $conf->{memory} || 512;
-    my $swap = $conf->{swap} // 0;
-
-    my $lxcmem = int($memory*1024*1024);
-    $raw .= "lxc.cgroup.memory.limit_in_bytes = $lxcmem\n";
+    if ($cgv1->{memory}) {
+	my $memory = $conf->{memory} || 512;
+	my $swap = $conf->{swap} // 0;
 
-    my $lxcswap = int(($memory + $swap)*1024*1024);
-    $raw .= "lxc.cgroup.memory.memsw.limit_in_bytes = $lxcswap\n";
+	my $lxcmem = int($memory*1024*1024);
+	$raw .= "lxc.cgroup.memory.limit_in_bytes = $lxcmem\n";
 
-    if (my $cpulimit = $conf->{cpulimit}) {
-	$raw .= "lxc.cgroup.cpu.cfs_period_us = 100000\n";
-	my $value = int(100000*$cpulimit);
-	$raw .= "lxc.cgroup.cpu.cfs_quota_us = $value\n";
+	my $lxcswap = int(($memory + $swap)*1024*1024);
+	$raw .= "lxc.cgroup.memory.memsw.limit_in_bytes = $lxcswap\n";
     }
 
-    my $shares = $conf->{cpuunits} || 1024;
-    $raw .= "lxc.cgroup.cpu.shares = $shares\n";
+    if ($cgv1->{cpu}) {
+	if (my $cpulimit = $conf->{cpulimit}) {
+	    $raw .= "lxc.cgroup.cpu.cfs_period_us = 100000\n";
+	    my $value = int(100000*$cpulimit);
+	    $raw .= "lxc.cgroup.cpu.cfs_quota_us = $value\n";
+	}
+
+	my $shares = $conf->{cpuunits} || 1024;
+	$raw .= "lxc.cgroup.cpu.shares = $shares\n";
+    }
 
     die "missing 'rootfs' configuration\n"
 	if !defined($conf->{rootfs});
@@ -436,28 +470,30 @@ sub update_lxc_config {
 	$raw .= "lxc.net.$ind.mtu = $d->{mtu}\n" if defined($d->{mtu});
     }
 
-    my $had_cpuset = 0;
-    if (my $lxcconf = $conf->{lxc}) {
-	foreach my $entry (@$lxcconf) {
-	    my ($k, $v) = @$entry;
-	    $had_cpuset = 1 if $k eq 'lxc.cgroup.cpuset.cpus';
-	    $raw .= "$k = $v\n";
+    if ($cgv1->{cpuset}) {
+	my $had_cpuset = 0;
+	if (my $lxcconf = $conf->{lxc}) {
+	    foreach my $entry (@$lxcconf) {
+		my ($k, $v) = @$entry;
+		$had_cpuset = 1 if $k eq 'lxc.cgroup.cpuset.cpus';
+		$raw .= "$k = $v\n";
+	    }
 	}
-    }
 
-    my $cores = $conf->{cores};
-    if (!$had_cpuset && $cores) {
-	my $cpuset = eval { PVE::CpuSet->new_from_cgroup('lxc', 'effective_cpus') };
-	$cpuset = PVE::CpuSet->new_from_cgroup('', 'effective_cpus') if !$cpuset;
-	my @members = $cpuset->members();
-	while (scalar(@members) > $cores) {
-	    my $randidx = int(rand(scalar(@members)));
-	    $cpuset->delete($members[$randidx]);
-	    splice(@members, $randidx, 1); # keep track of the changes
+	my $cores = $conf->{cores};
+	if (!$had_cpuset && $cores) {
+	    my $cpuset = eval { PVE::CpuSet->new_from_cgroup('lxc', 'effective_cpus') };
+	    $cpuset = PVE::CpuSet->new_from_cgroup('', 'effective_cpus') if !$cpuset;
+	    my @members = $cpuset->members();
+	    while (scalar(@members) > $cores) {
+		my $randidx = int(rand(scalar(@members)));
+		$cpuset->delete($members[$randidx]);
+		splice(@members, $randidx, 1); # keep track of the changes
+	    }
+	    $raw .= "lxc.cgroup.cpuset.cpus = ".$cpuset->short_string()."\n";
 	}
-	$raw .= "lxc.cgroup.cpuset.cpus = ".$cpuset->short_string()."\n";
     }
-    
+
     File::Path::mkpath("$dir/rootfs");
 
     PVE::Tools::file_set_contents("$dir/config", $raw);
-- 
2.11.0




More information about the pve-devel mailing list