When a module is being loaded directly from disk (no compression,
etc), pass the file descriptor to the new finit_module() syscall. If
finit_module is exported by glibc, use it. Otherwise, manually make
the syscall on architectures where it is known to exist.
---
libkmod/libkmod-file.c | 16 +++++++++++++++-
libkmod/libkmod-module.c | 18 ++++++++++++++++++
libkmod/libkmod-private.h | 2 ++
3 files changed, 35 insertions(+), 1 deletion(-)
diff --git a/libkmod/libkmod-file.c b/libkmod/libkmod-file.c
index ced20a8..76585f5 100644
--- a/libkmod/libkmod-file.c
+++ b/libkmod/libkmod-file.c
@@ -52,6 +52,7 @@ struct kmod_file {
gzFile gzf;
#endif
int fd;
+ int direct;
off_t size;
void *memory;
const struct file_ops *ops;
@@ -254,9 +255,11 @@ static int load_reg(struct kmod_file *file)
return -errno;
file->size = st.st_size;
- file->memory = mmap(0, file->size, PROT_READ, MAP_PRIVATE, file->fd, 0);
+ file->memory = mmap(NULL, file->size, PROT_READ, MAP_PRIVATE,
+ file->fd, 0);
if (file->memory == MAP_FAILED)
return -errno;
+ file->direct = 1;
return 0;
}
@@ -300,6 +303,7 @@ struct kmod_file *kmod_file_open(const struct kmod_ctx *ctx,
magic_size_max = itr->magic_size;
}
+ file->direct = 0;
if (magic_size_max > 0) {
char *buf = alloca(magic_size_max + 1);
ssize_t sz;
@@ -353,6 +357,16 @@ off_t kmod_file_get_size(const struct kmod_file *file)
return file->size;
}
+int kmod_file_get_direct(const struct kmod_file *file)
+{
+ return file->direct;
+}
+
+int kmod_file_get_fd(const struct kmod_file *file)
+{
+ return file->fd;
+}
+
void kmod_file_unref(struct kmod_file *file)
{
if (file->elf)
diff --git a/libkmod/libkmod-module.c b/libkmod/libkmod-module.c
index b1d40b1..5a9473a 100644
--- a/libkmod/libkmod-module.c
+++ b/libkmod/libkmod-module.c
@@ -33,6 +33,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>
+#include <sys/syscall.h>
#include <sys/wait.h>
#include <string.h>
#include <fnmatch.h>
@@ -763,6 +764,14 @@ KMOD_EXPORT int kmod_module_remove_module(struct
kmod_module *mod,
extern long init_module(const void *mem, unsigned long len, const char *args);
+#ifndef __NR_finit_module
+# define __NR_finit_module -1
+#endif
+static inline int finit_module(int fd, const char *uargs, int flags)
+{
+ return syscall(__NR_finit_module, fd, uargs, flags);
+}
+
/**
* kmod_module_insert_module:
* @mod: kmod module
@@ -803,6 +812,14 @@ KMOD_EXPORT int kmod_module_insert_module(struct
kmod_module *mod,
return err;
}
+ if (kmod_file_get_direct(file)) {
+ err = finit_module(kmod_file_get_fd(file), args,
+ flags & (KMOD_INSERT_FORCE_VERMAGIC |
+ KMOD_INSERT_FORCE_MODVERSION));
+ if (err == 0 || errno != ENOSYS)
+ goto init_finished;
+ }
+
size = kmod_file_get_size(file);
mem = kmod_file_get_contents(file);
@@ -829,6 +846,7 @@ KMOD_EXPORT int kmod_module_insert_module(struct
kmod_module *mod,
}
err = init_module(mem, size, args);
+init_finished:
if (err < 0) {
err = -errno;
INFO(mod->ctx, "Failed to insert module '%s': %m\n", path);
diff --git a/libkmod/libkmod-private.h b/libkmod/libkmod-private.h
index b472c62..c765003 100644
--- a/libkmod/libkmod-private.h
+++ b/libkmod/libkmod-private.h
@@ -142,6 +142,8 @@ struct kmod_file *kmod_file_open(const struct kmod_ctx
*ctx, const char *filenam
struct kmod_elf *kmod_file_get_elf(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)));
+int kmod_file_get_direct(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)));
/* libkmod-elf.c */
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe linux-modules" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html