aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLucas De Marchi <lucas.de.marchi@gmail.com>2023-06-01 15:39:57 -0700
committerLucas De Marchi <lucas.de.marchi@gmail.com>2023-06-09 10:45:51 -0700
commit7a86f1292051e990507ea48888864ff19626a206 (patch)
tree14059b9d89a9c4497c3b1a58068059299970756a
parent9c262fdb1c798fd87d91e8c669acbec4d632024b (diff)
downloadkmod-7a86f1292051e990507ea48888864ff19626a206.tar.gz
libkmod: Do not inititialize file->memory on open
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>
-rw-r--r--libkmod/libkmod-elf.c5
-rw-r--r--libkmod/libkmod-file.c21
-rw-r--r--libkmod/libkmod-internal.h3
-rw-r--r--libkmod/libkmod-module.c2
4 files changed, 27 insertions, 4 deletions
diff --git a/libkmod/libkmod-elf.c b/libkmod/libkmod-elf.c
index fb2e3d9..933825b 100644
--- a/libkmod/libkmod-elf.c
+++ b/libkmod/libkmod-elf.c
@@ -281,6 +281,11 @@ struct kmod_elf *kmod_elf_new(const void *memory, off_t size)
assert_cc(sizeof(uint32_t) == sizeof(Elf32_Word));
assert_cc(sizeof(uint32_t) == sizeof(Elf64_Word));
+ if (!memory) {
+ errno = -EINVAL;
+ return NULL;
+ }
+
class = elf_identify(memory, size);
if (class < 0) {
errno = -class;
diff --git a/libkmod/libkmod-file.c b/libkmod/libkmod-file.c
index b6a8cc9..08adea9 100644
--- a/libkmod/libkmod-file.c
+++ b/libkmod/libkmod-file.c
@@ -421,6 +421,7 @@ struct kmod_elf *kmod_file_get_elf(struct kmod_file *file)
if (file->elf)
return file->elf;
+ kmod_file_load_contents(file);
file->elf = kmod_elf_new(file->memory, file->size);
return file->elf;
}
@@ -431,7 +432,7 @@ struct kmod_file *kmod_file_open(const struct kmod_ctx *ctx,
struct kmod_file *file = calloc(1, sizeof(struct kmod_file));
const struct comp_type *itr;
size_t magic_size_max = 0;
- int err;
+ int err = 0;
if (file == NULL)
return NULL;
@@ -477,8 +478,8 @@ struct kmod_file *kmod_file_open(const struct kmod_ctx *ctx,
if (file->ops == NULL)
file->ops = &reg_ops;
- err = file->ops->load(file);
file->ctx = ctx;
+
error:
if (err < 0) {
if (file->fd >= 0)
@@ -491,6 +492,18 @@ error:
return file;
}
+/*
+ * Callers should just check file->memory got updated
+ */
+void kmod_file_load_contents(struct kmod_file *file)
+{
+ if (file->memory)
+ return;
+
+ /* The load functions already log possible errors. */
+ file->ops->load(file);
+}
+
void *kmod_file_get_contents(const struct kmod_file *file)
{
return file->memory;
@@ -516,7 +529,9 @@ void kmod_file_unref(struct kmod_file *file)
if (file->elf)
kmod_elf_unref(file->elf);
- file->ops->unload(file);
+ if (file->memory)
+ file->ops->unload(file);
+
if (file->fd >= 0)
close(file->fd);
free(file);
diff --git a/libkmod/libkmod-internal.h b/libkmod/libkmod-internal.h
index 4a4af58..3275bc5 100644
--- a/libkmod/libkmod-internal.h
+++ b/libkmod/libkmod-internal.h
@@ -152,6 +152,7 @@ bool kmod_module_is_builtin(struct kmod_module *mod) __attribute__((nonnull(1)))
/* libkmod-file.c */
struct kmod_file *kmod_file_open(const struct kmod_ctx *ctx, const char *filename) _must_check_ __attribute__((nonnull(1,2)));
struct kmod_elf *kmod_file_get_elf(struct kmod_file *file) __attribute__((nonnull(1)));
+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)));
@@ -166,7 +167,7 @@ struct kmod_modversion {
char *symbol;
};
-struct kmod_elf *kmod_elf_new(const void *memory, off_t size) _must_check_ __attribute__((nonnull(1)));
+struct kmod_elf *kmod_elf_new(const void *memory, off_t size) _must_check_;
void kmod_elf_unref(struct kmod_elf *elf) __attribute__((nonnull(1)));
const void *kmod_elf_get_memory(const struct kmod_elf *elf) _must_check_ __attribute__((nonnull(1)));
int kmod_elf_get_strings(const struct kmod_elf *elf, const char *section, char ***array) _must_check_ __attribute__((nonnull(1,2,3)));
diff --git a/libkmod/libkmod-module.c b/libkmod/libkmod-module.c
index 7736b7e..f352fe1 100644
--- a/libkmod/libkmod-module.c
+++ b/libkmod/libkmod-module.c
@@ -917,6 +917,8 @@ KMOD_EXPORT int kmod_module_insert_module(struct kmod_module *mod,
goto init_finished;
}
+ kmod_file_load_contents(mod->file);
+
if (flags & (KMOD_INSERT_FORCE_VERMAGIC | KMOD_INSERT_FORCE_MODVERSION)) {
elf = kmod_file_get_elf(mod->file);
if (elf == NULL) {