Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add fallback kernel version scraper #32

Merged
merged 1 commit into from Nov 29, 2021

Conversation

depau
Copy link
Contributor

@depau depau commented Jun 28, 2020

The kernel version scraper included in mkinitcpio works only on x86 kernel images.

This commit implements kernel version scraping on a generic architecture if an uncompressed image is provided.

With this commit I'm mainly targeting ALARM. However, since I wasn't able to find a static offset for the kernel version like on x86, I decided to go for a generic scraper that greps over the entire uncompressed image.

This is definitely inefficient, it takes ~300ms on my laptop with an NVMe SSD, 1.8s on my Rock64 with eMMC storage. However, it's better than nothing in my opinion, and people can still hardcode the kernel version in the preset just as before.

@falconindy
Copy link
Contributor

falconindy commented Jun 28, 2020

I can't see how this is correct. Versions need to be suitable for dropping into a file path to the module directory, but yours will include an irrelevant preamble of Linux version and whatever comes after the version. I'm also a little suspicious that this does not work on x86, where I expect it should.

This pull request should be 1 commit, not 4.

@depau
Copy link
Contributor Author

depau commented Jun 28, 2020

but yours will include an irrelevant preamble of Linux version and whatever comes after the version

Nope - this is linux-aarch64 from ALARM:

$ grep -aPo -m 1 'Linux version \d+(\.\d+)+.*' Image
Linux version 5.7.2-2-ARCH (builduser@leming) (gcc version 9.3.0 (GCC), GNU ld (GNU Binutils) 2.34) #1 SMP Tue Jun 16 12:48:51 UTC 2020

$ read _ _ kver _ < <(grep -aPo -m 1 'Linux version \d+(\.\d+)+.*' Image)
$ echo $kver
5.7.0-2-ARCH

I'm also a little suspicious that this does not work on x86, where I expect it should.

It does not, though I don't see the problem there. The banner is in the compressed chunk, so grep won't see it. It should work if you run it on a vmlinuX uncompressed image.

This is linux from Arch:

$ strings -a -t x /boot/vmlinuz-linux | grep '5\.7\.6'
   3a40 5.7.6-arch1-1 (linux@archlinux) #1 SMP PREEMPT Thu, 25 Jun 2020 00:14:47 +0000
 7145ac 5.7.6-arH
 71b7a0 5.7.6-arch1-1 (linux@archlinux) (gcc version 10.1.0 (GCC), GNU ld (GNU Binutils) 2.34.0) #1 SMP PREEMPT Thu, 25 Jun 2020 00:14:47 +0000

# ^^ not a banner

$ binwalk -e /boot/vmlinuz-linux

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             Microsoft executable, portable (PE)
16808         0x41A8          xz compressed data
7452976       0x71B930        xz compressed data

$ strings _vmlinuz-linux.extracted/41A8 | grep 'Linux version'
Linux version 5.7.6-arch1-1 (linux@archlinux) (gcc version 10.1.0 (GCC), GNU ld (GNU Binutils) 2.34.0) #1 SMP PREEMPT Thu, 25 Jun 2020 00:14:47 +0000

# ^^ this is the banner

The x86 kver extraction procedure is much more efficient and there's no reason to replace it with mine. This PR targets architectures for which:

  • An uncompressed image is also provided (such as ARM on ALARM)
  • A more efficient way to retrieve it is not available.

There might be edge cases like people disabling printk+procfs completely so maybe the banner doesn't end up in the image. Regardless of how likely this is, they'll get an error message just like before.

I spent a good hour or two this morning to read header files and linker scripts to see if I could find a well-known pointer to the location of a version string, like on x86. I couldn't find any. If anyone has a better approach I'd be way happier to save that 1.8s of my life spent watching mkinitcpio scan the kernel image, but until then this approach should be quite reliable and I think it is a good compromise.

This pull request should be 1 commit, not 4.

No problem, I can squash it into one when it's ready to merge. Update: squashed into one commit.

@depau
Copy link
Contributor Author

depau commented Jun 28, 2020

To add more context on why I think this is helpful:

As of now, linux packages on non-x86 derivates hardcode the kernel version in /etc/mkinitcpio.d/$pkgname.preset.

Cool, it works. But what if I want to change the preset to add, for instance, a fallback image? If were to do that, I'd have to remember every time I update the kernel to update the version number in the preset, because pacman is not going to touch it any more since I changed it.

Every time I forget to do it (which == every time I update the kernel) I have to grab a screwdriver, remove the eMMC module, slap it into a (very slow) USB adapter, mount it on my x86 laptop, chroot into it, update the preset, rerun mkinitcpio, make sure it runs the fallback image on next boot cause default isn't gonna work, put it back together.

That adds up to ~30m of work. I'd gladly trade that half hour with an extra 1.8s when I run mkinitcpio.

With this patch you can just point it to the kernel image and have it scrape it for you just like on x86, and enjoy custom presets.

Note that this does not imply alarm or whatever derivative's kernels should update their presets to use this. They can (and should IMHO, since it's faster), keep it hardcoded. This is just an additional way to scrape the kversion that users who want to make their custom presets can use.

Let me know if you have any questions

@grazzolini
Copy link
Member

I'm going over this PR and I think it's somewhat complex for little added benefit. Also, testing this is hard, because I would have to setup an arm VM in order to test it. I'll consider this for a future release of mkinitcpio.

@depau
Copy link
Contributor Author

depau commented Oct 28, 2020

I'm going over this PR and I think it's somewhat complex for little added benefit. Also, testing this is hard, because I would have to setup an arm VM in order to test it. I'll consider this for a future release of mkinitcpio.

If it can be helpful you can also test this on x86 using an ALARM aarch64/armv7h-generic rootfs and qemu-user-static (AUR).
You also need binfmt-qemu-static (also AUR), then you should be able to just chroot/systemd-nspawn into the rootfs, install linux-aarch64, mkinitcpio with my patches, modify /etc/mkinitcpio.d/linux-aarch64.preset so that ALL_kver points to /boot/Image and then test whether the initcpio generation works.

This is probably easier than bringing up an ARM VM since setting up the emulated hardware is not as straightforward as for x86 VMs.

@grazzolini
Copy link
Member

I'll try to test this, but for a future release of mkinitcpio

@tlahdekorpi
Copy link
Contributor

Using PCREs makes this way more expensive than it needs to be.

$ time command grep -aPo -m 1 'Linux version \d+(\.\d+)+.*' vmlinux > /dev/null

real	0m0.262s
user	0m0.255s
sys	0m0.006s

$ time command grep -m1 -aoE 'Linux version .(\.[-[:alnum:]]+)+' vmlinux > /dev/null

real	0m0.013s
user	0m0.006s
sys	0m0.007s

@depau
Copy link
Contributor Author

depau commented Feb 11, 2021

Thanks, it is indeed much faster:

[depau@sushi boot]$ time command grep -aPo -m 1 'Linux version \d+(\.\d+)+.*' Image
Linux version 5.10.12-1-ARCH (builduser@leming) (aarch64-unknown-linux-gnu-gcc (GCC) 10.2.0, GNU ld (GNU Binutils) 2.35) #1 SMP Sun Jan 31 13:17:28 MST 2021

real	0m0.595s
user	0m0.594s
sys	0m0.001s
[depau@sushi boot]$ time command grep -m1 -aoE 'Linux version .(\.[-[:alnum:]]+)+' Image
Linux version 5.10.12-1-ARCH

real	0m0.036s
user	0m0.023s
sys	0m0.012s

I'll add this change and rebase it on top of master while I'm at it

The kernel version scraper included in mkinitcpio works only on
x86 kernel images.
This commit implements kernel version scraping on a generic
architecture if an uncompressed image is provided.

Signed-off-by: Davide Depau <davide@depau.eu>
@adam900710
Copy link
Contributor

Can we get this feature merged?

I got a PR with similar modification: #45

The benefit will be that, all other Arch based distros (ALARM/ManjaroARM) can get a much simpler preset for their mkinicpio, no need to specify specific kernel version.
This is especially handy for kernel bisecting as each bisected kernel needs their initramfs generated.

@adam900710
Copy link
Contributor

Unfortunately this version is a little too strict, as it ignores the tailing +, which is pretty common for kernel with extra patches upon git tree.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants