aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLucas De Marchi <lucas.de.marchi@gmail.com>2023-06-01 15:40:01 -0700
committerLucas De Marchi <lucas.de.marchi@gmail.com>2023-06-20 14:39:25 -0700
commit09c9f8c5df0475d2627d9498e26250592dbfebd6 (patch)
tree2594d2f7eb0764022751385165fe0b0258e94506
parent30077bf1719eb9625b1c223c144b74285425d581 (diff)
downloadkmod-09c9f8c5df0475d2627d9498e26250592dbfebd6.tar.gz
libkmod: Use kernel decompression when available
With the recent changes to bypass loading the file it's possible to reduce the work in userspace and delegating it to the kernel. Without any compression to illustrate: Before: read(3, "\177ELF\2\1", 6) = 6 lseek(3, 0, SEEK_SET) = 0 newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=238592, ...}, AT_EMPTY_PATH) = 0 mmap(NULL, 238592, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fd85cbd1000 finit_module(3, "", 0) = 0 munmap(0x7fd85cbd1000, 238592) = 0 close(3) = 0 After: read(3, "\177ELF\2\1", 6) = 6 lseek(3, 0, SEEK_SET) = 0 finit_module(3, "", 0) = 0 close(3) = 0 When using kernel compression now it's also possible to direct libkmod to take the finit_module() path, avoiding the decompression in userspace and just delegating it to the kernel. Before: read(3, "(\265/\375\244\0", 6) = 6 lseek(3, 0, SEEK_SET) = 0 read(3, "(\265/\375\244", 5) = 5 mmap(NULL, 135168, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3fa431e000 read(3, "\0\244\3\0\\y\6", 7) = 7 mmap(NULL, 372736, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3fa414f000 brk(0x55944c6a1000) = 0x55944c6a1000 read(3, "\356|\6G\27U\20 \312\260s\211\335\333\263\326\330\336\273O\211\356\306K\360Z\341\374U6\342\221"..., 53038) = 53038 mremap(0x7f3fa431e000, 135168, 266240, MREMAP_MAYMOVE) = 0x7f3fa410e000 read(3, ",;\3\nqf\311\362\325\211\7\341\375A\355\221\371L\\\5\7\375 \32\246<(\258=K\304"..., 20851) = 20851 mremap(0x7f3fa410e000, 266240, 397312, MREMAP_MAYMOVE) = 0x7f3fa40ad000 read(3, ")\36\250\213", 4) = 4 read(3, "", 4) = 0 munmap(0x7f3fa414f000, 372736) = 0 init_module(0x7f3fa40ad010, 238592, "") = 0 munmap(0x7f3fa40ad000, 397312) = 0 close(3) = 0 After: read(3, "(\265/\375\244P", 6) = 6 lseek(3, 0, SEEK_SET) = 0 finit_module(3, "", 0x4 /* MODULE_INIT_??? */) = 0 close(3) = 0 Signed-off-by: Lucas De Marchi <lucas.de.marchi@gmail.com>
-rw-r--r--libkmod/libkmod-file.c4
-rw-r--r--libkmod/libkmod-internal.h3
-rw-r--r--libkmod/libkmod-module.c15
-rw-r--r--libkmod/libkmod.c5
4 files changed, 21 insertions, 6 deletions
diff --git a/libkmod/libkmod-file.c b/libkmod/libkmod-file.c
index ca9d06f..b138e7e 100644
--- a/libkmod/libkmod-file.c
+++ b/libkmod/libkmod-file.c
@@ -517,9 +517,9 @@ off_t kmod_file_get_size(const struct kmod_file *file)
return file->size;
}
-bool kmod_file_get_direct(const struct kmod_file *file)
+enum kmod_file_compression_type kmod_file_get_compression(const struct kmod_file *file)
{
- return file->compression == KMOD_FILE_COMPRESSION_NONE;
+ return file->compression;
}
int kmod_file_get_fd(const struct kmod_file *file)
diff --git a/libkmod/libkmod-internal.h b/libkmod/libkmod-internal.h
index d7ec1e4..26a7e28 100644
--- a/libkmod/libkmod-internal.h
+++ b/libkmod/libkmod-internal.h
@@ -112,6 +112,7 @@ void kmod_pool_add_module(struct kmod_ctx *ctx, struct kmod_module *mod, const c
void kmod_pool_del_module(struct kmod_ctx *ctx, struct kmod_module *mod, const char *key) __attribute__((nonnull(1, 2, 3)));
const struct kmod_config *kmod_get_config(const struct kmod_ctx *ctx) __attribute__((nonnull(1)));
+enum kmod_file_compression_type kmod_get_kernel_compression(const struct kmod_ctx *ctx) __attribute__((nonnull(1)));
/* libkmod-config.c */
struct kmod_config_path {
@@ -162,7 +163,7 @@ struct kmod_elf *kmod_file_get_elf(struct kmod_file *file) __attribute__((nonnul
void kmod_file_load_contents(struct kmod_file *file) __attribute__((nonnull(1)));
void *kmod_file_get_contents(const struct kmod_file *file) _must_check_ __attribute__((nonnull(1)));
off_t kmod_file_get_size(const struct kmod_file *file) _must_check_ __attribute__((nonnull(1)));
-bool kmod_file_get_direct(const struct kmod_file *file) _must_check_ __attribute__((nonnull(1)));
+enum kmod_file_compression_type kmod_file_get_compression(const struct kmod_file *file) _must_check_ __attribute__((nonnull(1)));
int kmod_file_get_fd(const struct kmod_file *file) _must_check_ __attribute__((nonnull(1)));
void kmod_file_unref(struct kmod_file *file) __attribute__((nonnull(1)));
diff --git a/libkmod/libkmod-module.c b/libkmod/libkmod-module.c
index 6ed5ad4..585da41 100644
--- a/libkmod/libkmod-module.c
+++ b/libkmod/libkmod-module.c
@@ -864,16 +864,25 @@ extern long init_module(const void *mem, unsigned long len, const char *args);
static int do_finit_module(struct kmod_module *mod, unsigned int flags,
const char *args)
{
+ enum kmod_file_compression_type compression, kernel_compression;
unsigned int kernel_flags = 0;
int err;
/*
- * Re-use ENOSYS, returned when there is no such syscall, so the
- * fallback to init_module applies
+ * When module is not compressed or its compression type matches the
+ * one in use by the kernel, there is no need to read the file
+ * in userspace. Otherwise, re-use ENOSYS to trigger the same fallback
+ * as when finit_module() is not supported.
*/
- if (!kmod_file_get_direct(mod->file))
+ compression = kmod_file_get_compression(mod->file);
+ kernel_compression = kmod_get_kernel_compression(mod->ctx);
+ if (!(compression == KMOD_FILE_COMPRESSION_NONE ||
+ compression == kernel_compression))
return -ENOSYS;
+ if (compression != KMOD_FILE_COMPRESSION_NONE)
+ kernel_flags |= MODULE_INIT_COMPRESSED_FILE;
+
if (flags & KMOD_INSERT_FORCE_VERMAGIC)
kernel_flags |= MODULE_INIT_IGNORE_VERMAGIC;
if (flags & KMOD_INSERT_FORCE_MODVERSION)
diff --git a/libkmod/libkmod.c b/libkmod/libkmod.c
index 103469e..1b8773c 100644
--- a/libkmod/libkmod.c
+++ b/libkmod/libkmod.c
@@ -1016,3 +1016,8 @@ const struct kmod_config *kmod_get_config(const struct kmod_ctx *ctx)
{
return ctx->config;
}
+
+enum kmod_file_compression_type kmod_get_kernel_compression(const struct kmod_ctx *ctx)
+{
+ return ctx->kernel_compression;
+}