Linux 退出…\n“; } 模块许可证(“GPL”); 模块_参数(pid,int,0); 模块参数(efd,int,0);
要运行此操作,请执行以下步骤:Linux 退出…\n“; } 模块许可证(“GPL”); 模块_参数(pid,int,0); 模块参数(efd,int,0);,linux,linux-kernel,Linux,Linux Kernel,要运行此操作,请执行以下步骤: 编译用户空间程序(efd_us.out)和内核模块(efd_lkm.ko) 运行用户空间程序(./efd_us.out)并记录它打印的pid和efd值。(例如,“pid=2803 efd=3”。用户空间程序将无休止地等待select() 打开一个新的终端窗口,并插入作为参数传递pid和efd的内核模块:sudo insmod efd_lkm.ko pid=2803 efd=3 切换回userspace程序窗口,您将看到userspace程序已脱离select并退出
我想做的是编写自己的协议栈作为内核模块,并创建类似于libc提供的socket函数的API。我将使用LD_PRELOAD编写自己版本的socket(),connect(),recv()等等。现在所有这些函数都在文件描述符上运行,我想保留它们的参数和返回类型。我的socket()版本将创建一个eventfd,并将描述符返回给用户空间应用程序。我需要告诉内核模块如何写入eventfd,以便任何等待的select()可以从中返回。嗨,彼得,在我发布问题之前,我确实尝试了你的建议。以下是结果:步骤1:我启动一个用户空间程序,创建和eventfd(),并在屏幕上打印fd值,然后再对其执行select()。步骤2:在一个单独的终端窗口中,我加载一个内核模块并传递fd值(在我的例子中是3,因为0,1,2对应于stdin、stdout和stderr)步骤3:LKM尝试使用eventfd_ctx_fdget()但返回一个错误。使用lsof,我看到3被分配给eventfd,但这是“3”“不是唯一标识的,因为不同的进程使用fds打开了文件=3@lithiumhead:您的内核模块需要在进程上下文中调用
eventfd\u ctx\u fdget()
。这就是为什么Peter建议通过ioctl()
传递它-ioctl处理程序在调用ioctl()的进程上下文中运行
@caf:嘿,谢谢你提供的信息,我一直在想这个问题,也就是说,如何在进程上下文中执行内核内部的操作!知道这一点将帮助我改进ioctl操作!@LitiumHead嗨,你能提供一些建议,告诉我如何向用户空间发送更多数据,而不仅仅是加号计数器吗在一个事件中?实际上这就是我开始做的。我使用ioctl来传输大块数据(而不仅仅是加号数据)在用户空间和内核空间之间。但是我需要内核驱动程序告诉用户空间程序我的数据已经准备好通过ioctl获取。所以您使用eventfd和ioctl.eventfd来发送信号,ioctl来传输数据。大多数内核空间行可以替换为“efd_ctx=eventfd_ctx_fdget(efd);”无需先查找任务,然后查找文件,再查找eventfd。
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h> //Definition of uint64_t
#include <sys/eventfd.h>
int efd; //Eventfd file descriptor
uint64_t eftd_ctr;
int retval; //for select()
fd_set rfds; //for select()
int s;
int main() {
//Create eventfd
efd = eventfd(0,0);
if (efd == -1){
printf("\nUnable to create eventfd! Exiting...\n");
exit(EXIT_FAILURE);
}
printf("\nefd=%d pid=%d",efd,getpid());
//Watch efd
FD_ZERO(&rfds);
FD_SET(efd, &rfds);
printf("\nNow waiting on select()...");
fflush(stdout);
retval = select(efd+1, &rfds, NULL, NULL, NULL);
if (retval == -1){
printf("\nselect() error. Exiting...");
exit(EXIT_FAILURE);
} else if (retval > 0) {
printf("\nselect() says data is available now. Exiting...");
printf("\nreturned from select(), now executing read()...");
s = read(efd, &eftd_ctr, sizeof(uint64_t));
if (s != sizeof(uint64_t)){
printf("\neventfd read error. Exiting...");
} else {
printf("\nReturned from read(), value read = %lld",eftd_ctr);
}
} else if (retval == 0) {
printf("\nselect() says that no data was available");
}
printf("\nClosing eventfd. Exiting...");
close(efd);
printf("\n");
exit(EXIT_SUCCESS);
}
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pid.h>
#include <linux/sched.h>
#include <linux/fdtable.h>
#include <linux/rcupdate.h>
#include <linux/eventfd.h>
//Received from userspace. Process ID and eventfd's File descriptor are enough to uniquely identify an eventfd object.
int pid;
int efd;
//Resolved references...
struct task_struct * userspace_task = NULL; //...to userspace program's task struct
struct file * efd_file = NULL; //...to eventfd's file struct
struct eventfd_ctx * efd_ctx = NULL; //...and finally to eventfd context
//Increment Counter by 1
static uint64_t plus_one = 1;
int init_module(void) {
printk(KERN_ALERT "~~~Received from userspace: pid=%d efd=%d\n",pid,efd);
userspace_task = pid_task(find_vpid(pid), PIDTYPE_PID);
printk(KERN_ALERT "~~~Resolved pointer to the userspace program's task struct: %p\n",userspace_task);
printk(KERN_ALERT "~~~Resolved pointer to the userspace program's files struct: %p\n",userspace_task->files);
rcu_read_lock();
efd_file = fcheck_files(userspace_task->files, efd);
rcu_read_unlock();
printk(KERN_ALERT "~~~Resolved pointer to the userspace program's eventfd's file struct: %p\n",efd_file);
efd_ctx = eventfd_ctx_fileget(efd_file);
if (!efd_ctx) {
printk(KERN_ALERT "~~~eventfd_ctx_fileget() Jhol, Bye.\n");
return -1;
}
printk(KERN_ALERT "~~~Resolved pointer to the userspace program's eventfd's context: %p\n",efd_ctx);
eventfd_signal(efd_ctx, plus_one);
printk(KERN_ALERT "~~~Incremented userspace program's eventfd's counter by 1\n");
eventfd_ctx_put(efd_ctx);
return 0;
}
void cleanup_module(void) {
printk(KERN_ALERT "~~~Module Exiting...\n");
}
MODULE_LICENSE("GPL");
module_param(pid, int, 0);
module_param(efd, int, 0);