gpt4 book ai didi

linux - 使用 Cpuset 将内核模块隔离到特定内核

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

从用户空间我们可以使用cpuset实际上隔离我们系统中的一个特定核心,并只对该核心执行一个特定进程。

我正在尝试对内核模块做同样的事情。所以我希望模块在一个独立的核心中执行。换句话说:如何在内核模块中使用 cpuset *

使用 linux/cpuset.h在我的内核模块中不起作用。所以,我有一个这样的模块:

#include <linux/module.h>
#include <linux/cpuset.h>

...
#ifdef CONFIG_CPUSETS
printk(KERN_INFO, "cpusets is enabled!");
#endif
cpuset_init(); // this function is declared in cpuset.h
...

尝试加载此模块时,我收到(在 dmesg 中)以下消息 cpusets is enabled!。但我也收到消息 Unknown symbol cpu_init (err 0)

同样,我尝试使用 linux/sched.h 中的 sched_setaffinity 将所有正在运行的进程移动到特定核心,然后将我的模块运行到一个独立的核心。我收到相同的错误消息:Unknown symbol sched_setaffinity (err 0)。我想我得到了“未知符号”,因为这些函数在内核中没有 EXPORT_SYMBOL。所以我去尝试调用 sys_sched_setaffinity 系统调用(基于此 question )但再次收到此消息:Unknown symbol sys_sched_setaffinity (err 0)!

此外,我不是在寻找使用 isolcpus 的解决方案,它是在启动时设置的。我只想加载模块,然后进行隔离。

  • (更准确地说,我希望它的内核线程在隔离的内核中执行。我知道我可以使用亲和力将线程绑定(bind)到特定内核,但这并不能保证内核会运行被在其上运行的其他进程隔离。)

最佳答案

So I want the module to get executed in an isolated core.

actually isolate a specific core in our system and execute just one specific process to that core

这是在使用内核 3.16 的 Debian 机器上编译和测试的有效源代码。我会先描述如何加载和卸载,以及传递的参数是什么意思。

所有资源都可以在 github 上找到...

https://github.com/harryjackson/doc/tree/master/linux/kernel/toy/toy

构建并加载模块...

make
insmod toy param_cpu_id=2

卸载模块使用

rmmod toy

我没有使用 modprobe,因为它需要一些配置等。我们传递给 toy 内核模块的参数是我们要隔离的 CPU。除非在该 CPU 上执行,否则被调用的设备操作都不会运行。

加载模块后,您可以在此处找到它

/dev/toy

简单的操作如

cat /dev/toy

创建内核模块捕获并产生一些输出的事件。您可以使用 dmesg 查看输出。

源代码...

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Harry");
MODULE_DESCRIPTION("toy kernel module");
MODULE_VERSION("0.1");
#define DEVICE_NAME "toy"
#define CLASS_NAME "toy"

static int param_cpu_id;
module_param(param_cpu_id , int, (S_IRUSR | S_IRGRP | S_IROTH));
MODULE_PARM_DESC(param_cpu_id, "CPU ID that operations run on");

//static void bar(void *arg);
//static void foo(void *cpu);
static int toy_open( struct inode *inodep, struct file *fp);
static ssize_t toy_read( struct file *fp , char *buffer, size_t len, loff_t * offset);
static ssize_t toy_write( struct file *fp , const char *buffer, size_t len, loff_t *);
static int toy_release(struct inode *inodep, struct file *fp);

static struct file_operations toy_fops = {
.owner = THIS_MODULE,
.open = toy_open,
.read = toy_read,
.write = toy_write,
.release = toy_release,
};

static struct miscdevice toy_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "toy",
.fops = &toy_fops
};

//static int CPU_IDS[64] = {0};
static int toy_open(struct inode *inodep, struct file *filep) {
int this_cpu = get_cpu();
printk(KERN_INFO "open: called on CPU:%d\n", this_cpu);
if(this_cpu == param_cpu_id) {
printk(KERN_INFO "open: is on requested CPU: %d\n", smp_processor_id());
}
else {
printk(KERN_INFO "open: not on requested CPU:%d\n", smp_processor_id());
}
put_cpu();
return 0;
}
static ssize_t toy_read(struct file *filep, char *buffer, size_t len, loff_t *offset){
int this_cpu = get_cpu();
printk(KERN_INFO "read: called on CPU:%d\n", this_cpu);
if(this_cpu == param_cpu_id) {
printk(KERN_INFO "read: is on requested CPU: %d\n", smp_processor_id());
}
else {
printk(KERN_INFO "read: not on requested CPU:%d\n", smp_processor_id());
}
put_cpu();
return 0;
}
static ssize_t toy_write(struct file *filep, const char *buffer, size_t len, loff_t *offset){
int this_cpu = get_cpu();
printk(KERN_INFO "write called on CPU:%d\n", this_cpu);
if(this_cpu == param_cpu_id) {
printk(KERN_INFO "write: is on requested CPU: %d\n", smp_processor_id());
}
else {
printk(KERN_INFO "write: not on requested CPU:%d\n", smp_processor_id());
}
put_cpu();
return 0;
}
static int toy_release(struct inode *inodep, struct file *filep){
int this_cpu = get_cpu();
printk(KERN_INFO "release called on CPU:%d\n", this_cpu);
if(this_cpu == param_cpu_id) {
printk(KERN_INFO "release: is on requested CPU: %d\n", smp_processor_id());
}
else {
printk(KERN_INFO "release: not on requested CPU:%d\n", smp_processor_id());
}
put_cpu();
return 0;
}

static int __init toy_init(void) {
int cpu_id;
if(param_cpu_id < 0 || param_cpu_id > 4) {
printk(KERN_INFO "toy: unable to load module without cpu parameter\n");
return -1;
}
printk(KERN_INFO "toy: loading to device driver, param_cpu_id: %d\n", param_cpu_id);
//preempt_disable(); // See notes below
cpu_id = get_cpu();
printk(KERN_INFO "toy init called and running on CPU: %d\n", cpu_id);
misc_register(&toy_device);
//preempt_enable(); // See notes below
put_cpu();
//smp_call_function_single(1,foo,(void *)(uintptr_t) 1,1);
return 0;
}

static void __exit toy_exit(void) {
misc_deregister(&toy_device);
printk(KERN_INFO "toy exit called\n");
}

module_init(toy_init);
module_exit(toy_exit);

上面的代码包含您要求的两种方法,即隔离 CPU 和在隔离内核上运行 init

在 init get_cpu 上禁用抢占,即在它之后发生的任何事情都不会被内核抢占,而是在一个内核上运行。请注意,这是使用 3.16 内核完成的,您的里程可能会因内核版本而异,但我认为这些 API 已经存在很长时间了

这是生成文件...

obj-m += toy.o

all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

注释。 get_cpulinux/smp.h 中声明为

#define get_cpu()   ({ preempt_disable(); smp_processor_id(); })
#define put_cpu() preempt_enable()

因此您实际上不需要在调用 get_cpu 之前调用 preempt_disable。get_cpu 调用是对以下调用序列的包装...

preempt_count_inc();
barrier();

而 put_cpu 确实在这样做......

barrier();
if (unlikely(preempt_count_dec_and_test())) {
__preempt_schedule();
}

使用上面的方法你可以随心所欲。几乎所有这些都取自以下来源..

谷歌... smp_call_function_single

Linux 内核开发,Robert Love 着。

http://derekmolloy.ie/writing-a-linux-kernel-module-part-2-a-character-device/

https://github.com/vsinitsyn/reverse/blob/master/reverse.c

关于linux - 使用 Cpuset 将内核模块隔离到特定内核,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36288877/

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