diff --git a/xCAT-server/share/xcat/netboot/ubuntu/genimage b/xCAT-server/share/xcat/netboot/ubuntu/genimage index 17005cdb5..9fe0803b4 100755 --- a/xCAT-server/share/xcat/netboot/ubuntu/genimage +++ b/xCAT-server/share/xcat/netboot/ubuntu/genimage @@ -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) = @_;