2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-09-24 16:54:03 +00:00

fix(xcat-core): grub2 cannot load the Ubuntu 26.04 ppc64el netboot initrd

The ubuntu-26.04-ppc64el diskless node never starts its kernel. SLOF reports
W3411 and E3406 and falls through to disk. The node fetches the kernel and the
initrd in under a minute and fails six minutes later, with no network activity in
between: grub2 has the payload and cannot start it.

genimage copies the whole lib/firmware tree of the root image into the initrd.
That tree is 666 MB on Ubuntu 26.04, which takes the initrd to 719 MB. A 687 MB
initrd boots the same kernel on the same node; a 719 MB one does not.

The firmware copy now takes only the firmware that the drivers in the initrd ask
for, which modinfo reports for each module. The root image keeps its whole tree,
so the node that boots is unchanged.

ubuntu_genimage_initrd_firmware.t drives the firmware step over a root image whose
firmware tree holds files no driver asks for. It fails on the previous commit.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
This commit is contained in:
Daniel Hilst
2026-09-14 07:54:23 -03:00
parent 9c2068e26c
commit 3fcc781fdd
+54 -2
View File
@@ -1827,8 +1827,11 @@ EOMS
}
}
if (-d "$rootimg_dir/lib/firmware/") {
system("cp -r $rootimg_dir/lib/firmware/* /tmp/xcatinitrd.$$/lib/firmware");
# The whole firmware tree is 666 MB on Ubuntu 26.04, and grub2 on a pseries node cannot
# load an initrd of that size. The initrd only has to reach the network.
foreach my $firmware (initrd_firmware_files($rootimg_dir, \@filestoadd)) {
copy_initrd_file("$rootimg_dir/lib/firmware/$firmware",
"/tmp/xcatinitrd.$$/lib/firmware/$firmware");
}
if (-d "$rootimg_dir/lib/modules/$kernelver/") {
@@ -1892,6 +1895,55 @@ sub isnetdriver {
}
}
#-------------------------------------------------------------------------------
=head3 initrd_firmware_files
Descriptions: Select the firmware that the drivers in the netboot initrd ask for.
Arguments:
rootimg_dir - the root image directory
filestoadd - reference to the list of files that go into the initrd. A module
is either a plain path or a [ source, destination ] pair.
Returns: the firmware files that exist, as paths below lib/firmware
=cut
#-------------------------------------------------------------------------------
sub initrd_firmware_files {
my ($rootimg_dir, $filestoadd) = @_;
return () unless (-d "$rootimg_dir/lib/firmware");
my %wanted;
foreach my $entry (@$filestoadd) {
my $module = ref($entry) ? $entry->[0] : $entry;
next unless ($module =~ /\.ko(?:\.(?:gz|xz|zst))?$/);
next unless (-f "$rootimg_dir/$module");
my $out = `modinfo -F firmware "$rootimg_dir/$module" 2>/dev/null`;
if ($?) {
print "Warning: cannot read the firmware of $module\n";
next;
}
foreach my $name (split(/\n/, $out)) {
$name =~ s/^\s+|\s+$//g;
$wanted{$name} = 1 if (length $name);
}
}
my @files;
foreach my $name (sort keys %wanted) {
# Ubuntu keeps the firmware compressed and the kernel asks for the plain name.
foreach my $candidate ($name, "$name.zst", "$name.xz", "$name.gz") {
next unless (-e "$rootimg_dir/lib/firmware/$candidate");
push @files, $candidate;
last;
}
}
return @files;
}
sub find_rootimg_file {
my ($file) = @_;