Move zstd-related function to a separate file so it's easier to isolate
the dependency on each decompression library.
Reviewed-by: Emil Velikov <emil.l.velikov@gmail.com>
Link: https://github.com/kmod-project/kmod/pull/58
Signed-off-by: Lucas De Marchi <lucas.de.marchi@gmail.com>
Move zlib-related function to a separate file so it's easier to isolate
the dependency on each decompression library.
Reviewed-by: Emil Velikov <emil.l.velikov@gmail.com>
Link: https://github.com/kmod-project/kmod/pull/58
Signed-off-by: Lucas De Marchi <lucas.de.marchi@gmail.com>
Move xz-related function to a separate file so it's easier to isolate
the dependency on each decompression library.
Declare struct kmod_file in a shared libkmod-internal-file.h that will
be included only by sources implementing kmod_file decompression
routines.
Reviewed-by: Emil Velikov <emil.l.velikov@gmail.com>
Link: https://github.com/kmod-project/kmod/pull/58
Signed-off-by: Lucas De Marchi <lucas.de.marchi@gmail.com>
The allocator in glibc has a particular quirk that successive
reallocs on the same pointer are cheap, at the cost of excess
memory fragmentation. Other allocators generally do not do this,
so excessive reallocs become relatively expensive.
Reducing the number of reallocations by using a more agressive
strategy for buffer size increase makes performance better on
those setups, e.g. musl libc, or generally any other allocator;
on my Chimera Linux setup with Scudo allocator (LLVM) it doubles
to triples the performance of running e.g. depmod.
Signed-off-by: q66 <q66@chimera-linux.org>
Signed-off-by: Lucas De Marchi <lucas.de.marchi@gmail.com>
It's cleaner to handle all compression types and load functions in the
same style.
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: Lucas De Marchi <lucas.de.marchi@gmail.com>
We're about to reference it in comp_types with next commit.
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: Lucas De Marchi <lucas.de.marchi@gmail.com>
This commit cleans up the indentation and the error path of the
function. It bears no functional changes.
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
[ Move assert to avoid warning with -Wdeclaration-after-statement ]
Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: Lucas De Marchi <lucas.de.marchi@gmail.com>
Since all the compression magic is always available now, we don't need
to loop at runtime nor use alloca - latter of which comes with a handful
of caveats.
Simply throw in a few assert_cc(), which will trigger at build-time.
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: Lucas De Marchi <lucas.de.marchi@gmail.com>
Currently, when built w/o given compression we'll incorrectly report a
"compression_none".
As we reach do_finit_module(), we'll naively assume that the kernel can
handle the compressed module, yet omit the MODULE_INIT_COMPRESSED_FILE
flag.
As result the kernel will barf at us, do_finit_module will fail with non
-ENOSYS and we won't end in the do_init_module codepath (which will also
fail).
In other words: with this change, you can build kmod without zstd, xz
and zlib support and the kernel will load the modules, assuming it
supports the format \o/
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: Lucas De Marchi <lucas.de.marchi@gmail.com>
Propagate any errors during decompression further up the call stack.
Without this we could easily pass NULL as mem to init_module(2).
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: Lucas De Marchi <lucas.de.marchi@gmail.com>
With the previous commits, we removed the need for a distinct unload
callback.
So nuke the struct all together and only use/keep the load one around.
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: Lucas De Marchi <lucas.de.marchi@gmail.com>
On mmap failure file->memory is set to -1, which we'll happily pass down
to munmap later on.
More importantly, since we do a NULL check in kmod_file_load_contents()
we will exit the function without (re)attempting the load again.
Since we ignore the return code for the load function(s), one can end up
calling kmod_elf_get_memory() and feed that -1 into init_module.
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: Lucas De Marchi <lucas.de.marchi@gmail.com>
These are used to protect a free(file->memory), within their respective
unload functions. Where the sole caller of the unload function already
does a NULL check prior.
Even so, free(NULL) is guaranteed to be safe by the standard.
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: Lucas De Marchi <lucas.de.marchi@gmail.com>
There is no need to keep the root gzFile context open for the whole
duration. Once we've copied the decompressed module to file->memory we
can close the handle.
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: Lucas De Marchi <lucas.de.marchi@gmail.com>
The gzdopen() API used, takes ownership of the fd. To make that more
explicit we clear it (-1) as applicable.
Yet again, kmod has explicit API to return the fd to the user - which
currently is used solely when uncompressed, so we're safe.
Regardless - simply duplicate the fd locally and use that with zlib.
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: Lucas De Marchi <lucas.de.marchi@gmail.com>
Do not only set the type as direct, but also keep track of the
compression being used. This will allow using the in-kernel compression
in future.
Reviewed-by: Luis Chamberlain <mcgrof@kernel.org>
Signed-off-by: Lucas De Marchi <lucas.de.marchi@gmail.com>
Add a separate function to load the file contents when it's needed.
When it's not needed on the path of loading modules via finit_module(),
there is no need to mmap the file. This will help support loading
modules with the in-kernel compression support.
This is done differently than the lazy initialization for
kmod_file_get_elf() because on the contents case there is also the
file->size to be updated. It would be a weird API to return the pointer
and have the size changed as a side-effect.
Signed-off-by: Lucas De Marchi <lucas.de.marchi@gmail.com>
I changed the style of the hackargs variable in autogen.sh to multiline
because said line was becoming a bit long with the new --with-zstd arg
added.
A previous version of this patch has been running on my two Arch Linux
installations (with an accompanying mkinitcpio patch) for several months
over many kernel updates without any issues.
Any additional testing and/or patch review would of course be appreciated.
Signed-off-by: Torge Matthies <openglfreak@googlemail.com>
It has changed in the past, and these days, anyone can get a copy of the
LGPL via the web rather than by post.
Like 657a122 (Remove FSF mailing address) in libabc by Josh Tripplet,
but let the FSF website in which the license can be found.
When a module is being loaded directly from disk (no compression, etc),
pass the file descriptor to the new finit_module() syscall. If the
finit_module syscall is exported by the kernel syscall headers, use it.
Additionally, if the kernel's module.h file is available, map kmod flags
to finit_module flags.
If we are accessing several times the modules and reading some sections
by sucessive calls to the functions below, we are incurring in a penalty
of having to open, parse the header and close the file. For each
function.
- kmod_module_get_info()
- kmod_module_get_versions()
- kmod_module_get_symbols()
- kmod_module_get_dependency_symbols()
These functions are particularly important to depmod. It calls all of
them, for each module. Moreover there's a huge bottleneck in the open
operation if we are using compression. Every time we open the module we
need to uncompress the file and after getting the information we need we
discard the result. This is clearly shown by profiling depmod with perf
(record + report), using compressed modules:
64.07% depmod libz.so.1.2.7 [.] 0x00000000000074b8 ◆
18.18% depmod libz.so.1.2.7 [.] crc32 ▒
2.42% depmod libz.so.1.2.7 [.] inflate ▒
1.17% depmod libc-2.16.so [.] __memcpy_ssse3_back ▒
0.96% depmod [kernel.kallsyms] [k] copy_user_generic_string ▒
0.89% depmod libc-2.16.so [.] __strcmp_sse42 ▒
0.82% depmod [kernel.kallsyms] [k] hrtimer_interrupt ▒
0.77% depmod libc-2.16.so [.] _int_malloc ▒
0.44% depmod kmod-nolib [.] kmod_elf_get_strings ▒
0.41% depmod kmod-nolib [.] kmod_elf_get_dependency_symbols ▒
0.37% depmod kmod-nolib [.] kmod_elf_get_section ▒
0.36% depmod kmod-nolib [.] kmod_elf_get_symbols
...
Average of running depmod 5 times, dropping caches between them, in a
slow spinning disk:
Before: 12.25 +- 0.20
After: 8.20 +- 0.21
m-i-t: 9.62 +- 0.27
So this patch leads to an improvement of ~33% over unpatched version,
ending up with 15% speedup over module-init-tools.
zlib won't necessarily set the system errno, and this is particularly
evident on corrupted data (which results in a double free). Use zlib's
gzerror to detect the failure, returning a generic EINVAL when zlib
doesn't provide us with an errno.
Refactor code to use pointer to functions, avoiding the previous
Now comp_types defines a magic header to be checked (size and bytes),
with the associated load() and unload() operations. If a header
matches, their operations are used. Otherwise the regular file
operations (mmap/munmap) are used.
File descriptor close is managed by the common code if it's valid
(>=0). If some code steals the file descriptor (eg: gzopen), then they
must change file->fd to -1.
This way the code should be easier to extend and avoid bugs.
Just now realized that my distro (Gentoo) enables support for gzip but
does not compress modules by default.
In this case it's better to have a special case that uses mmap()
instead of a loop of realloc() + gzread().