栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

从内核模块写入eventfd

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

从内核模块写入eventfd

我终于想出了怎么做。我意识到,系统上的每个打开文件都可以由打开该文件的进程之一的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);

要运行此程序,请执行以下步骤:

  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. 切换回用户空间程序窗口,您将看到用户空间程序已脱离选择并退出。


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/417240.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号