Ответ 1
Наконец-то я понял, как это сделать. Я понял, что каждый открытый файл в системе может быть идентифицирован pid одного из процессов, которые его открыли, и fd, соответствующего этому файлу (в этом контексте процесса). Поэтому, если мой модуль ядра знает pid и fd, он может искать struct * task_struct процесса и из него struct * files и, наконец, использовать fd, it может получить указатель на файл eventfd struct *. Затем, используя этот последний указатель, он может записать счетчик eventfd.
Вот коды для программы userpace и модуля ядра, которые я написал, чтобы продемонстрировать концепцию (которая теперь работает):
Код пользователя 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 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 task struct
struct file * efd_file = NULL; //...to eventfd 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 task struct: %p\n",userspace_task);
printk(KERN_ALERT "~~~Resolved pointer to the userspace program 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 eventfd 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 eventfd context: %p\n",efd_ctx);
eventfd_signal(efd_ctx, plus_one);
printk(KERN_ALERT "~~~Incremented userspace program eventfd 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);
Чтобы выполнить это, выполните следующие шаги:
- Скомпилируйте программу пользовательского пространства (efd_us.out) и модуль ядра (efd_lkm.ko)
- Запустите программу пользовательского пространства (./efd_us.out) и обратите внимание на значения pid и efd, которые он печатает. (например, "pid = 2803 efd = 3". Программа пользовательского пространства будет бесконечно ждать при выборе()
- Откройте новое окно терминала и вставьте модуль ядра, передающий pid и efd в качестве параметров: sudo insmod efd_lkm.ko pid = 2803 efd = 3
- Вернитесь в окно программы пользовательской программы, и вы увидите, что программа пользовательского пространства вышла из выбора и вышла.