oe-lite / core

Official OE-lite/core repository - moved to GitLab.com
https://gitlab.com/oe-lite/core
Other
4 stars 17 forks source link

fetch/git.py: uniformize mtimes of checked-out files #224

Closed Villemoes closed 7 years ago

Villemoes commented 7 years ago

This fixes a subtle and hard-to-reproduce error when building the linux kernel and modules, and should be The Right Thing To Do in general. The symptom, when the bug appears, is that the kernel is built with some version string "4.5.6-01234-g0abcdef", but the modules (both the native kernel modules and those built externally using the linux-dev package) end up in /lib/modules/4.5.6-01234-g0abcdef-dirty.

The problem turned out to be that when we do 'git checkout -q', the files

arch/arm/crypto/aesbs-core.S_shipped arch/arm/crypto/bsaes-armv7.pl

sometimes ended up with the latter being newer than the former (in the vast majority of cases, their mtimes are identical due to the limited resolution of filesystem timestamps), which in turn causes the kernel build system to (re)generate aesbs-core.S_shipped by running the perl script.

Now, when we build vmlinux, the kernel build system calls scripts/setlocalversion rather early to generate include/config/kernel.release. setlocalversion in turn uses 'git diff-index HEAD' to decide whether the kernel tree is dirty. At this point in time it is not, so include/config/kernel.release is create with the contents "4.5.6-01234-g0abcdef".

Later during the same build, Make detects that the .S_shipped is older than the perl script, so it gets recreated. Since it is updated with ">" shell redirection, the dev and ino stays the same, so does the content, but the mtime is obviously updated.

If we then go on to do a "make LOADADDR=0x1234 uImage", the kernel build system again calls setlocalversion, and this time "git diff-index --name-only HEAD" actually produces output (namely, arch/arm/crypto/aesbs-core.S_shipped), so include/config/kernel.release is recreated, this time containing "4.5.6-01234-g0abcdef-dirty". The right version string was already baked into vmlinux, so the resulting kernel shows that for uname -r, but everything from now on, including internal and external module builds, ends up using the -dirty string.

When I hit this problem, the time stamps of the files above were 4 ms apart (which is exactly one jiffy since I have CONFIG_HZ=250, so apparently that's my filesystem timestamp granularity). This explains why it's hard to reproduce; a timer tick must hit between git creating the two files in question (and if it happened to create them in the other order it would never be seen). Similar problems can happen anywhere a git repository contains files which are generated by a Makefile rule, making the build inherently non-deterministic.

So instead of having all the checked-out files having almost-but-not-quite the same mtime, make them really have the same time.

However, this now totally wreaks git's view of the world, since all mtimes and ctimes are now different from what was recorded in the index during checkout, which in turn means that the very first run of setlocalversion would treat the kernel tree as dirty. While deterministic, we don't want all kernel version strings to contain -dirty, so fix this up by refreshing the index after the mtime-settings.