gpt4 book ai didi

linux - 从内核模块写入 eventfd

转载 作者:IT王子 更新时间:2023-10-29 00:19:39 27 4
gpt4 key购买 nike

我已经使用 eventfd() 在用户空间程序中创建了一个 eventfd 实例。有没有一种方法可以将一些引用(指向其结构或 pid+fd 对的指针)传递给这个创建的 eventfd 实例到内核模块,以便它可以更新计数器值?

这是我想做的:我正在开发一个用户空间程序,它需要与我编写的内核空间模块交换数据和信号。为了传输数据,我已经在使用 ioctl。但我希望内核模块能够在新数据准备好通过 ioctl 使用时向用户空间程序发出信号。

为此,我的用户空间程序将在不同的线程中创建一些 eventfds。这些线程将使用 select() 在这些 eventfds 上等待,每当内核模块更新这些 eventfds 上的计数时,它们将通过 ioctl 请求它来继续使用数据。

问题是,如何从内核空间解析指向这些 eventfds 的“struct file *”指针?我可以向内核模块发送哪些关于 eventfds 的信息,以便它可以获得指向 eventfds 的指针?我将在内核模块中使用哪些函数来获取这些指针?

是否有更好的方法从内核空间向用户空间发送事件信号?我不能放弃使用 select()。

最佳答案

我终于想出了如何做到这一点。我意识到系统上每个打开的文件都可以通过打开它的进程之一的 pid 和对应于该文件的 fd(在该进程的上下文中)来识别。因此,如果我的内核模块知道 pid 和 fd,它可以查找进程的 struct * task_structstruct * files,最后使用 fd,它可以获得指向 eventfd 的 struct * file 的指针。然后,使用最后一个指针,它可以写入 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 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);
}

内核模块 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 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);

要运行它,请执行以下步骤:

  1. 编译用户空间程序(efd_us.out)和内核模块(efd_lkm.ko)
  2. 运行用户空间程序 (./efd_us.out) 并记下它打印的 pid 和 efd 值。 (例如“pid=2803 efd=3”。用户空间程序将无休止地等待 select()
  3. 打开一个新的终端窗口并插入传递 pid 和 efd 作为参数的内核模块:sudo insmod efd_lkm.ko pid=2803 efd=3
  4. 切换回用户空间程序窗口,你会看到用户空间程序已经脱离select退出。

关于linux - 从内核模块写入 eventfd,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13607730/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com