use PVE::Tools;
use PVE::ProcFSTools;
-my $MAX_CPUID;
-
-sub max_cpuid {
-
- return $MAX_CPUID if defined($MAX_CPUID);
-
- my $cpuinfo = PVE::ProcFSTools::read_cpuinfo();
-
- $MAX_CPUID = $cpuinfo->{cpus} || 1;
-
- return $MAX_CPUID;
-}
-
sub new {
- my ($this) = @_;
+ my ($class, $members) = @_;
- my $class = ref($this) || $this;
+ $members //= {};
+ my $self = bless { members => $members }, $class;
- my $self = bless { members => {} }, $class;
-
- max_cpuid() if !defined($MAX_CPUID); # initialize $MAX_CPUID
-
return $self;
}
+# Create a new set with the contents of a cgroup-v1 subdirectory.
+# Deprecated:
sub new_from_cgroup {
- my ($this, $cgroup, $kind) = @_;
+ my ($class, $cgroup, $effective) = @_;
+
+ return $class->new_from_path("/sys/fs/cgroup/cpuset/$cgroup", $effective);
+}
- $kind //= 'cpus';
+# Create a new set from the contents of a complete path to a cgroup directory.
+sub new_from_path {
+ my ($class, $path, $effective) = @_;
+
+ my $filename;
+ if ($effective) {
+ $filename = "$path/cpuset.effective_cpus";
+ if (!-e $filename) {
+ # cgroupv2:
+ $filename = "$path/cpuset.cpus.effective";
+ }
+ } else {
+ $filename = "$path/cpuset.cpus";
+ }
- my $filename = "/sys/fs/cgroup/cpuset/$cgroup/cpuset.$kind";
my $set_text = PVE::Tools::file_read_firstline($filename) // '';
- my $cpuset = $this->new();
-
- my $members = $cpuset->{members};
+ my ($count, $members) = parse_cpuset($set_text);
+ return $class->new($members);
+}
+
+sub parse_cpuset {
+ my ($set_text) = @_;
+
+ my $members = {};
my $count = 0;
foreach my $part (split(/,/, $set_text)) {
if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
my ($from, $to) = ($1, $2);
$to //= $1;
- die "cpu id '$from' is out of range\n" if $from >= $MAX_CPUID;
- die "cpu id '$to' is out of range\n" if $to >= $MAX_CPUID;
die "invalid range: $part ($to < $from)\n" if $to < $from;
for (my $i = $from; $i <= $to; $i++) {
$members->{$i} = 1;
}
}
- die "got empty cpuset for cgroup '$cgroup'\n"
- if !$count;
-
- return $cpuset;
+ return ($count, $members);
}
+# Deprecated:
sub write_to_cgroup {
my ($self, $cgroup) = @_;
- my $filename = "/sys/fs/cgroup/cpuset/$cgroup/cpuset.cpus";
+ return $self->write_to_path("/sys/fs/cgroup/cpuset/$cgroup");
+}
+
+# Takes the cgroup directory containing the cpuset.cpus file (to be closer to
+# new_from_path behavior this doesn't take the complete file name).
+sub write_to_path {
+ my ($self, $path) = @_;
+
+ my $filename = "$path/cpuset.cpus";
my $value = '';
my @members = $self->members();
$value .= $cpuid;
}
- die "unable to write empty cpu set\n" if !length($value);
-
open(my $fh, '>', $filename) || die "failed to open '$filename' - $!\n";
PVE::Tools::safe_print($filename, $fh, "$value\n");
close($fh) || die "failed to close '$filename' - $!\n";
my ($self, @members) = @_;
my $count = 0;
-
+
foreach my $cpu (@members) {
- die "cpu id '$cpu' is out of range\n" if $cpu >= $MAX_CPUID;
next if $self->{members}->{$cpu};
$self->{members}->{$cpu} = 1;
$count++;
my ($self, @members) = @_;
my $count = 0;
-
+
foreach my $cpu (@members) {
- die "cpu id '$cpu' is out of range\n" if $cpu >= $MAX_CPUID;
next if !$self->{members}->{$cpu};
delete $self->{members}->{$cpu};
$count++;
sub members {
my ($self) = @_;
- return sort keys %{$self->{members}};
-}
+ my @sorted_members = sort { $a <=> $b } keys %{$self->{members}};
+ return @sorted_members;
+}
sub size {
my ($self) = @_;
foreach my $id (keys %$members2) {
return 0 if !$members1->{$id};
}
-
+
return 1;
}