无法从模块访问内核函数符号 sys_epoll_create1
Cannot access kernel function symbol sys_epoll_create1 from module
我正在编写一个驱动程序作为模块。我必须从模块调用系统调用 sys_epoll_create1()
。我写了一个这样的模块:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/net.h>
#include <linux/syscalls.h>
#include <linux/eventpoll.h>
#include <net/sock.h>
MODULE_LICENSE("GPL");
static int hello_init(void)
{
sys_epoll_create1(1);
return 0;
}
static void hello_exit(void)
{
}
module_init(hello_init);
module_exit(hello_exit);
编译日志是这样的:
~/test $ make
make -C /lib/modules/4.2.0-16-generic/build M=/home/kyl/test modules
make[1]: Entering directory '/usr/src/linux-headers-4.2.0-16-generic'
CC [M] /home/kyl/test/hello.o
Building modules, stage 2.
MODPOST 1 modules
WARNING: "sys_epoll_create1" [/home/kyl/test/hello.ko] undefined!
CC /home/kyl/test/hello.mod.o
LD [M] /home/kyl/test/hello.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.2.0-16-generic'
正如我检查的那样,linux/syscalls.h
中有一个sys_epoll_create1()
的声明
asmlinkage long sys_epoll_create1(int flags);
我已经将 <linux/syscalls.h>
作为头文件,为什么 gcc 仍然显示 WARNING: "sys_epoll_create1" [/home/kyl/test/hello.ko] undefined!
?
Linux 内核不再导出 (EXPORT_SYMBOL
) 系统调用实现(sys_*
函数)。例如,参见 this question 关于 sys_read 和 sys_open。与导出 vfs_*
替换的 reading/writing 文件不同,epoll 相关函数不会为模块导出,因此您不能 epoll_create1
文件描述符和 return 它给用户。
但是可以在内核模块中实现某种 select
/poll
系统调用。为监视器存储文件描述符列表的方式可以是任意一种。
#include <linux/poll.h>
void my_select(void)
{
struct poll_wqueues table;
poll_initwait(&table);
poll_table *wait = &table.pt;
for(;;) {
// Call ->poll() for every file descriptor(*i*) which is monitored
for(<i in monitored files>) {
struct fd f = fdget(i);
if(f.file) {
const struct file_operations *f_op = f.file->f_op;
int mask_output = DEFAULT_POLLMASK; // Mask of available events
int mask_input = <mask of events which are monitored for given file>;
if(f_op) {
wait->_key = mask_input;
mask_output = f_op->poll(f.file, wait);
}
if(mask_output & mask_input) {
// Some requested events are available. Mark that fact in some way.
}
}
}
if(<some requested events have fired>) break;
// Important: Make futher calls to ->proc not adding wait into waitqueue.
wait->_proc = NULL;
// Wait events if they are not fired already.
// For timeout waits *poll_schedule_timeout* can be used.
poll_schedule(&table, TASK_INTERRUPTIBLE);
}
poll_freewait(&table);
}
这实际上是核函数的简化实现do_select,所以你可以查看更多细节。
驱动程序中使用了类似的轮询机制serial2002。但它忘记在等待迭代之间清除 ->_proc
字段,因此在长时间等待和许多虚假唤醒的情况下可以获得 ENOMEM。
我正在编写一个驱动程序作为模块。我必须从模块调用系统调用 sys_epoll_create1()
。我写了一个这样的模块:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/net.h>
#include <linux/syscalls.h>
#include <linux/eventpoll.h>
#include <net/sock.h>
MODULE_LICENSE("GPL");
static int hello_init(void)
{
sys_epoll_create1(1);
return 0;
}
static void hello_exit(void)
{
}
module_init(hello_init);
module_exit(hello_exit);
编译日志是这样的:
~/test $ make
make -C /lib/modules/4.2.0-16-generic/build M=/home/kyl/test modules
make[1]: Entering directory '/usr/src/linux-headers-4.2.0-16-generic'
CC [M] /home/kyl/test/hello.o
Building modules, stage 2.
MODPOST 1 modules
WARNING: "sys_epoll_create1" [/home/kyl/test/hello.ko] undefined!
CC /home/kyl/test/hello.mod.o
LD [M] /home/kyl/test/hello.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.2.0-16-generic'
正如我检查的那样,linux/syscalls.h
sys_epoll_create1()
的声明
asmlinkage long sys_epoll_create1(int flags);
我已经将 <linux/syscalls.h>
作为头文件,为什么 gcc 仍然显示 WARNING: "sys_epoll_create1" [/home/kyl/test/hello.ko] undefined!
?
Linux 内核不再导出 (EXPORT_SYMBOL
) 系统调用实现(sys_*
函数)。例如,参见 this question 关于 sys_read 和 sys_open。与导出 vfs_*
替换的 reading/writing 文件不同,epoll 相关函数不会为模块导出,因此您不能 epoll_create1
文件描述符和 return 它给用户。
但是可以在内核模块中实现某种 select
/poll
系统调用。为监视器存储文件描述符列表的方式可以是任意一种。
#include <linux/poll.h>
void my_select(void)
{
struct poll_wqueues table;
poll_initwait(&table);
poll_table *wait = &table.pt;
for(;;) {
// Call ->poll() for every file descriptor(*i*) which is monitored
for(<i in monitored files>) {
struct fd f = fdget(i);
if(f.file) {
const struct file_operations *f_op = f.file->f_op;
int mask_output = DEFAULT_POLLMASK; // Mask of available events
int mask_input = <mask of events which are monitored for given file>;
if(f_op) {
wait->_key = mask_input;
mask_output = f_op->poll(f.file, wait);
}
if(mask_output & mask_input) {
// Some requested events are available. Mark that fact in some way.
}
}
}
if(<some requested events have fired>) break;
// Important: Make futher calls to ->proc not adding wait into waitqueue.
wait->_proc = NULL;
// Wait events if they are not fired already.
// For timeout waits *poll_schedule_timeout* can be used.
poll_schedule(&table, TASK_INTERRUPTIBLE);
}
poll_freewait(&table);
}
这实际上是核函数的简化实现do_select,所以你可以查看更多细节。
驱动程序中使用了类似的轮询机制serial2002。但它忘记在等待迭代之间清除 ->_proc
字段,因此在长时间等待和许多虚假唤醒的情况下可以获得 ENOMEM。