Re: [PATCH] bpf: fix build for BPF preload when $(O) points to a relative path

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



2021-01-26 11:24 UTC+0000 ~ Quentin Monnet <quentin@xxxxxxxxxxxxx>
> 2021-01-25 16:32 UTC-0800 ~ Andrii Nakryiko <andrii.nakryiko@xxxxxxxxx>
>> On Mon, Jan 25, 2021 at 7:49 AM Quentin Monnet <quentin@xxxxxxxxxxxxx> wrote:
>>>
>>> Building the kernel with CONFIG_BPF_PRELOAD, and by providing a relative
>>> path for the output directory, may fail with the following error:
>>>
>>>   $ make O=build bindeb-pkg
>>>   ...
>>>   /.../linux/tools/scripts/Makefile.include:5: *** O=build does not exist.  Stop.
>>>   make[7]: *** [/.../linux/kernel/bpf/preload/Makefile:9: kernel/bpf/preload/libbpf.a] Error 2
>>>   make[6]: *** [/.../linux/scripts/Makefile.build:500: kernel/bpf/preload] Error 2
>>>   make[5]: *** [/.../linux/scripts/Makefile.build:500: kernel/bpf] Error 2
>>>   make[4]: *** [/.../linux/Makefile:1799: kernel] Error 2
>>>   make[4]: *** Waiting for unfinished jobs....
>>>
>>> In the case above, for the "bindeb-pkg" target, the error is produced by
>>> the "dummy" check in Makefile.include, called from libbpf's Makefile.
>>> This check changes directory to $(PWD) before checking for the existence
>>> of $(O). But at this step we have $(PWD) pointing to "/.../linux/build",
>>> and $(O) pointing to "build". So the Makefile.include tries in fact to
>>> assert the existence of a directory named "/.../linux/build/build",
>>> which does not exist.
>>>
>>> By contrast, other tools called from the main Linux Makefile get the
>>> variable set to $(abspath $(objtree)), where $(objtree) is ".". We can
>>> update the Makefile for kernel/bpf/preload to set $(O) to the same
>>> value, to permit compiling with a relative path for output. Note that
>>> apart from the Makefile.include, the variable $(O) is not used in
>>> libbpf's build system.
>>>
>>> Note that the error does not occur for all make targets and
>>> architectures combinations.
>>>
>>> - On x86, "make O=build vmlinux" appears to work fine.
>>>   $(PWD) points to "/.../linux/tools", but $(O) points to the absolute
>>>   path "/.../linux/build" and the test succeeds.
>>> - On UML, it has been reported to fail with a message similar to the
>>>   above (see [0]).
>>> - On x86, "make O=build bindeb-pkg" fails, as described above.
>>>
>>> It is unsure where the different values for $(O) and $(PWD) come from
>>> (likely some recursive make with different arguments at some point), and
>>> because several targets are broken, it feels safer to fix the $(O) value
>>> passed to libbpf rather than to hunt down all changes to the variable.
>>>
>>> David Gow previously posted a slightly different version of this patch
>>> as a RFC [0], two months ago or so.
>>>
>>> [0] https://lore.kernel.org/bpf/20201119085022.3606135-1-davidgow@xxxxxxxxxx/t/#u
>>>
>>> Cc: Andrii Nakryiko <andrii.nakryiko@xxxxxxxxx>
>>> Cc: Brendan Higgins <brendanhiggins@xxxxxxxxxx>
>>> Cc: David Gow <davidgow@xxxxxxxxxx>
>>> Reported-by: David Gow <davidgow@xxxxxxxxxx>
>>> Signed-off-by: Quentin Monnet <quentin@xxxxxxxxxxxxx>
>>> ---
>>
>> I still think it would benefit everyone to figure out where this is
>> breaking (given Linux Makefile explicitly tries to handle such
>> relative path situation for O=, I believe), but this is trivial
>> enough, so:
>>
>> Acked-by: Andrii Nakryiko <andrii@xxxxxxxxxx>
> 
> Agreed, I'll try to spend a bit more time on this when I can. But it
> would be nice to have the fix in the meantime. Thanks for the review and
> ack.

+Cc Masahiro Yamada

Looking further into this, my understanding is the following.

tools/scripts/Makefile.include contains this check:

	dummy := $(if $(shell cd $(PWD); test -d $(O) || \
		echo $(O)),$(error O=$(O) does not exist),)
	ABSOLUTE_O := $(shell cd $(PWD); cd $(O) ; pwd)

Note the use of $(PWD). As I understand, it is the shell environment
variable, as it was set when the initial "make" command was run. This
seems to be passed down to recursive calls to make. So if I type

	$ cd /linux
	$ make O=build vmlinux

Then I get $(PWD) set to "/linux" and $(O) set to "build". The Makefile
executes a submake from the output directory:

	# Invoke a second make in the output directory, passing relevant
	# variables
	__sub-make:
		$(Q)$(MAKE) -C $(abs_objtree) \
			-f $(abs_srctree)/Makefile $(MAKECMDGOALS)

But the variables are preserved. So far, so good.

When I try to build "bindeb-pkg" instead:

	$ cd /linux
	$ make O=build bindeb-pkg

Then I initially set $(PWD) and $(O) to the same values. They are
preserved after the call to the submake, after we have changed to the
output directory. But if I understand correctly, the "bindeb-pkg" target
writes a new Makefile as build/debian/rules in scripts/package/mkdebian,
and calls it _indirectly_ through dpkg-buildpackage, which does _not_
preserve $(PWD) (instead, it is reset to /linux/build, the current
directory when calling the script). I end up with $(O) set to "build",
and $(PWD) set to "/linux/build". The "dummy" check called for libbpf
fails to find "/linux/build/build".

Can we avoid using $(PWD) in the first place? I'm not sure how. It was
added in commit be40920fbf10 ("tools: Let O= makes handle a relative
path with -C option") to accommodate building perf with "-C", so we
could not replace $(PWD) with $$PWD (shell value at the time the
directive is executed) for example, the values will be different.

Can we unset $(O) so that, when we call dpkg-buildpackage, it reflects
the output directory relatively to /linux/build/? Or pass a value for
$(PWD), so it is preserved? Maybe, I don't know. It could be done in
scripts/package/mkdebian for example, by passing "O=''" to the make
call. It seems that the packages build well with this change. But then
we might need to check and update the other packages too (RPM, snap,
perf archives), and identify if something similar might be happening for
UML. I'm not sure this is worth the trouble at this point, if all we
want is to fix the eBPF preloads? But I'm open to discussion if this is
really the path we want to go.

Fixing $(O) to pass the dummy check is easier. However, when reading the
commits I noticed that my patch is incorrect. It would break on
something like "make O=~/build bindeb-pkg", because abspath does not
resolve special shell characters like "~". See also commit 028568d84da3
("kbuild: revert $(realpath ...) to $(shell cd ... && /bin/pwd)"): this
is why tools/scripts/Makefile.include still has an "ABSOLUTE_O"
variable. So instead of setting "O=$(abspath .)", I'll send a v2 with
Andrii's suggestion to use $(LIBBPF_OUT).

Quentin



[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux