我终于想出了怎么做。我意识到,系统上的每个打开文件都可以由打开该文件的进程之一的pid以及与该文件相对应的fd标识(在该进程的上下文中)。因此,如果我的内核模块知道pid和fd,则可以查找进程的
struct * task_struct ,并从中查找 struct *文件 ,最后使用fd,它可以获取指向eventfd的
struct *文件 的指针。然后,使用最后一个指针,它可以写入eventfd的计数器。
这是我为演示该概念而编写的用户空间程序和内核模块的代码(现已可用):
用户空间C代码(efd_us.c):
#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <stdint.h> //Definition of uint64_t#include <sys/eventfd.h>int efd; //Eventfd file descriptoruint64_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);}内核模块C代码(efd_lkm.c):
#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 structstruct file * efd_file = NULL; //...to eventfd's file structstruct eventfd_ctx * efd_ctx = NULL; //...and finally to eventfd context//Increment Counter by 1static uint64_t plus_one = 1;int init_module(void) { printk(KERN_alert "~~~Received from userspace: pid=%d efd=%dn",pid,efd); userspace_task = pid_task(find_vpid(pid), PIDTYPE_PID); printk(KERN_alert "~~~Resolved pointer to the userspace program's task struct: %pn",userspace_task); printk(KERN_alert "~~~Resolved pointer to the userspace program's files struct: %pn",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: %pn",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: %pn",efd_ctx); eventfd_signal(efd_ctx, plus_one); printk(KERN_alert "~~~Incremented userspace program's eventfd's counter by 1n"); 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);要运行此程序,请执行以下步骤:
- 编译用户空间程序(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
- 切换回用户空间程序窗口,您将看到用户空间程序已脱离选择并退出。



