From 0b6a2f0ec53a90d3c3f253a201ef303cafda259e Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Thu, 21 Jun 2018 10:07:41 +0200 Subject: [PATCH] deal with disabled cgroup subsystems 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 --- 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 16cd4ec..6296d6f 100755 --- a/src/PVE/CLI/pct.pm +++ b/src/PVE/CLI/pct.pm @@ -661,6 +661,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.39.5