从用户空间,我们可以使用cpuset实际 隔离系统中 的特定核心,并仅对该核心执行一个特定进程。
我正在尝试对内核模块执行相同的操作。因此,我希望模块在隔离的内核中执行。换句话说: 如何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)。
dmesg
cpusets is enabled!
Unknown symbol cpu_init (err 0)
同样,我尝试使用sched_setaffinityfrom linux/sched.h来将所有正在运行的过程移至特定的内核,然后将模块运行至隔离的内核。我收到了相同的错误消息:Unknown symbolsched_setaffinity (err0)。我猜我得到了“未知符号”,因为这些功能EXPORT_SYMBOL在内核中没有。所以我去,并试图调用`sys_sched_setaffinity
sched_setaffinity
linux/sched.h
Unknown symbolsched_setaffinity (err0)
EXPORT_SYMBOL
此外,我不是在寻找使用的解决方案,该解决方案isolcpus是在引导时设置的。我只想加载模块,然后进行隔离操作。
isolcpus
因此,我希望模块在隔离的内核中执行。
和
实际上隔离了我们系统中的特定核心并仅对该核心执行一个特定过程
这是一个有效的源代码,使用内核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上执行,否则它们将不会运行。
toy
加载模块后,您可以在此处找到它
/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已经存在了很长时间
get_cpu
这是Makefile …
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_cpu被声明linux/smp.h为
linux/smp.h
#define get_cpu() ({ preempt_disable(); smp_processor_id(); }) #define put_cpu() preempt_enable()
因此您实际上不需要在致电preempt_disable之前致电get_cpu。get_cpu调用是以下调用序列的包装。
preempt_disable
preempt_count_inc(); barrier();
而put_cpu实际上就是这样做的…
barrier(); if (unlikely(preempt_count_dec_and_test())) { __preempt_schedule(); }
使用上面的方法,您可以任意选择。几乎所有这些都来自以下来源。
Google for … 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