diff --git a/sys/compat/linuxkpi/common/include/linux/module.h b/sys/compat/linuxkpi/common/include/linux/module.h --- a/sys/compat/linuxkpi/common/include/linux/module.h +++ b/sys/compat/linuxkpi/common/include/linux/module.h @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include @@ -51,7 +53,26 @@ #define MODULE_SUPPORTED_DEVICE(name) #define MODULE_IMPORT_NS(_name) +/* + * THIS_MODULE is used to differentiate modules on Linux. We currently + * completely stub out any Linux struct module usage, but THIS_MODULE is still + * used to populate the "owner" fields of various drivers. Even though we + * don't actually dereference these "owner" fields they are still used by + * drivers to check if devices/dmabufs/etc come from different modules. For + * example, during DRM GEM import some drivers check if the dmabuf's owner + * matches the dev's owner. If they match because they are both NULL drivers + * may incorrectly think two resources come from the same module. + * + * To handle this we specify an undefined symbol __this_linker_file, which + * will get special treatment from the linker when resolving. This will + * populate the usages of __this_linker_file with the linker_file_t of the + * module. + */ +#ifdef KLD_MODULE +#define THIS_MODULE ((struct module *)&__this_linker_file) +#else #define THIS_MODULE ((struct module *)0) +#endif #define __MODULE_STRING(x) __stringify(x) @@ -97,9 +118,33 @@ #define module_exit_order(fn, order) \ SYSUNINIT(fn, SI_SUB_OFED_MODINIT, (order), _module_run, (fn)) -#define module_get(module) -#define module_put(module) -#define try_module_get(module) 1 +/* + * linuxkpi modules use struct module *, but this is really the FreeBSD struct + * module instead of a linux one. These modules are populated by THIS_MODULE, which + * is a macro that's really a casted pointer to the linker file for this module. So + * to bump the reference count we cast it to a linker file, and then up the file's + * refcount + */ +static inline void +module_get(struct module *module) +{ + linker_file_t file = (linker_file_t)module; + file->refs++; +} + +static inline void +module_put(struct module *module) +{ + linker_file_t file = (linker_file_t)module; + file->refs--; +} + +static inline int +try_module_get(struct module *module) +{ + module_get(module); + return 1; +} #define postcore_initcall(fn) module_init(fn) diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c --- a/sys/kern/kern_linker.c +++ b/sys/kern/kern_linker.c @@ -906,6 +906,20 @@ KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%p, name=%s, deps=%d\n", file, name, deps)); + /* + * Treat the __this_linker_file as a special symbol. This is a global that + * linuxkpi uses to populate the THIS_MODULE value. In this case we can + * simply return the linker_file_t. + * + * Modules compiled statically into the kernel are assigned NULL. + */ + if (strcmp(name, "__this_linker_file") == 0) { + address = file == linker_kernel_file ? NULL : (caddr_t)file; + KLD_DPF(SYM, ("linker_file_lookup_symbol: resolving special symbol" + " __this_linker_file to %p\n", address)); + return (address); + } + if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) { LINKER_SYMBOL_VALUES(file, sym, &symval); if (symval.value == 0) diff --git a/sys/sys/linker.h b/sys/sys/linker.h --- a/sys/sys/linker.h +++ b/sys/sys/linker.h @@ -44,6 +44,11 @@ * Object representing a file which has been loaded by the linker. */ typedef struct linker_file* linker_file_t; +/* + * Special symbol which will be replaced by a reference to the linker_file_t + * of the module it is used in. + */ +extern linker_file_t __this_linker_file; typedef TAILQ_HEAD(, linker_file) linker_file_list_t; typedef caddr_t linker_sym_t; /* opaque symbol */